#include <GL/glew.h>

#include <glm/glm.hpp> 
#include <glm/gtc/matrix_transform.hpp> 
#include <glm/gtx/transform2.hpp> 
#include <glm/gtx/projection.hpp>

#include <myWindow.h>
   
#include <iostream>
#include <fstream>
#include <vector>
#include <cstdio>
#include <SOIL.h>

#define CAMERA_WASD 0
#define CAMERA_ORBIT 1
#define CAMERA_CRANE 2
#define _USE_MATH_DEFINES
#include <math.h>
using namespace std;

float flag = false;
int cameraPerspectiveType = CAMERA_WASD;
float global_time;


bool shadows = false;
bool firstPass = false;

int shadowMapWidth = 3024;
int shadowMapHeight = 3024;

void myWindow::createCube()
{
    if (this->cube_vertex_buffer != NULL)
    {
        delete this->cube_vertex_buffer;
    }
    this->cube_vertex_buffer_size = 3*8;
    this->cube_vertex_buffer = new GLfloat[this->cube_vertex_buffer_size];

    if (this->cube_normal_buffer != NULL)
    {
        delete this->cube_normal_buffer;
    }
    this->cube_normal_buffer_size = 3*8;
    this->cube_normal_buffer = new GLfloat[this->cube_normal_buffer_size];
    
    if (this->cube_index_buffer != NULL)
    {
        delete this->cube_index_buffer;
    }
    this->cube_index_buffer_size = 4 * 6;
    this->cube_index_buffer = new GLuint[this->cube_index_buffer_size];

    this->cube_vertex_buffer[0] = 0.5f;
    this->cube_vertex_buffer[1] = 0.5f;
    this->cube_vertex_buffer[2] = -0.5f;

    this->cube_vertex_buffer[3] = 0.5f;
    this->cube_vertex_buffer[4] = -0.5f;
    this->cube_vertex_buffer[5] = -0.5f;

    this->cube_vertex_buffer[6] = -0.5f;
    this->cube_vertex_buffer[7] = -0.5f;
    this->cube_vertex_buffer[8] = -0.5f;

    this->cube_vertex_buffer[9] = -0.5f;
    this->cube_vertex_buffer[10] = 0.5f;
    this->cube_vertex_buffer[11] = -0.5f;

    this->cube_vertex_buffer[12] = 0.5f;
    this->cube_vertex_buffer[13] = 0.5f;
    this->cube_vertex_buffer[14] = 0.5f;

    this->cube_vertex_buffer[15] = 0.5f;
    this->cube_vertex_buffer[16] = -0.5f;
    this->cube_vertex_buffer[17] = 0.5f;

    this->cube_vertex_buffer[18] = -0.5f;
    this->cube_vertex_buffer[19] = -0.5f;
    this->cube_vertex_buffer[20] = 0.5f;

    this->cube_vertex_buffer[21] = -0.5f;
    this->cube_vertex_buffer[22] = 0.5f;
    this->cube_vertex_buffer[23] = 0.5f;

    this->cube_index_buffer[0] = 0;
    this->cube_index_buffer[1] = 1;
    this->cube_index_buffer[2] = 2;
    this->cube_index_buffer[3] = 3;
 
    this->cube_index_buffer[4] = 4;
    this->cube_index_buffer[5] = 5;
    this->cube_index_buffer[6] = 6;
    this->cube_index_buffer[7] = 7;
    
    this->cube_index_buffer[8] = 0;
    this->cube_index_buffer[9] = 4;
    this->cube_index_buffer[10] = 5;
    this->cube_index_buffer[11] = 1;

    this->cube_index_buffer[12] = 1;
    this->cube_index_buffer[13] = 5;
    this->cube_index_buffer[14] = 6;
    this->cube_index_buffer[15] = 2;

    this->cube_index_buffer[16] = 2;
    this->cube_index_buffer[17] = 6;
    this->cube_index_buffer[18] = 7;
    this->cube_index_buffer[19] = 3;

    this->cube_index_buffer[20] = 3;
    this->cube_index_buffer[21] = 7;
    this->cube_index_buffer[22] = 4;
    this->cube_index_buffer[23] = 0;

    this->cube_normal_buffer[0] = 0.5f;
    this->cube_normal_buffer[1] = 0.5f;
    this->cube_normal_buffer[2] = 0.0f;

    this->cube_normal_buffer[3] = 0.5f;
    this->cube_normal_buffer[4] = -0.5f;
    this->cube_normal_buffer[5] = 0.0f;

    this->cube_normal_buffer[6] = -0.5f;
    this->cube_normal_buffer[7] = -0.5f;
    this->cube_normal_buffer[8] = 0.0f;

    this->cube_normal_buffer[9] = -0.5f;
    this->cube_normal_buffer[10] = 0.5f;
    this->cube_normal_buffer[11] = 0.0f;

    this->cube_normal_buffer[12] = 0.5f;
    this->cube_normal_buffer[13] = 0.5f;
    this->cube_normal_buffer[14] = 0.0f;

    this->cube_normal_buffer[15] = 0.5f;
    this->cube_normal_buffer[16] = -0.5f;
    this->cube_normal_buffer[17] = 0.0f;

    this->cube_normal_buffer[18] = -0.5f;
    this->cube_normal_buffer[19] = -0.5f;
    this->cube_normal_buffer[20] = 0.0f;

    this->cube_normal_buffer[21] = -0.5f;
    this->cube_normal_buffer[22] = 0.5f;
    this->cube_normal_buffer[23] = 0.0f;
}

void  myWindow::loadTexture(const char* filename){
    // Load texture file
   	int image_witdh;
	int image_height;
	int image_channels;

	//glActiveTexture(GL_TEXTURE0);

	GLuint id = SOIL_load_OGL_texture (filename, SOIL_LOAD_AUTO, SOIL_CREATE_NEW_ID, SOIL_FLAG_TEXTURE_REPEATS | SOIL_FLAG_COMPRESS_TO_DXT);
	/* check for an error during the load process */
	if (0 == id) {
		printf("SOIL loading error for file %s: '%s'\n",filename, SOIL_last_result());
	}	

	textures[filename] = id;

  }

void  myWindow::loadTextures(){
	
	const int nTextures = 24;
	char* filenames[nTextures] = {
		"textures/grass.png",
		"textures/marble.png",
		"textures/brushedmetal.png",
		"textures/marble-normalmap.png",
		"textures/leaf.png",
		"textures/trunk.png",
		"textures/skybox/otop18.jpg",
		"textures/skybox/oback18.jpg",
		"textures/skybox/oright18.jpg",
		"textures/skybox/oleft18.jpg",
		"textures/skybox/ofront18.jpg",
		"textures/sand.png",
		"textures/asphalt.png",
		"textures/metalBrushed.png",
		"textures/floor.png",
		"textures/floor-normalmap.png",
		"textures/wood.png",
		"textures/metal.png",
		"textures/glass.png",
		"textures/dirt.png",
		"textures/depthTexture.png",
		"textures/reflection.jpg",
		"textures/brick.jpg",
		"textures/brick-normalmap.png"
	};

	for (int i = 0 ; i < nTextures ; i++){
		loadTexture(filenames[i]);
	}	
	
}

	
void myWindow::initTexture(const char* filename){
	glActiveTexture(GL_TEXTURE0);
	glBindTexture(GL_TEXTURE_2D, textures[filename]);
	
	if (shadows){
		int loc = glGetUniformLocation(this->textureProgramHandle, "Tex1");
		if (loc>= 0 ){
			glUniform1i(loc, 0);
		} else {
			cerr << "Error al inicializar " << filename << " en Tex1 de texture" << endl;
		}

		loc = glGetUniformLocation(this->normalMappingProgramHandle, "Tex1");
		if (loc>= 0 ){
			glUniform1i(loc, 0);
		} else {
			cerr << "Error al inicializar " << filename << " en Tex1 de texture" << endl;
		}
	} else {
		int loc = glGetUniformLocation(this->textureNONSHADOWProgramHandle, "Tex1");
		if (loc>= 0 ){
			glUniform1i(loc, 0);
		} else {
			cerr << "Error al inicializar " << filename << " en Tex1 de textureNONSHADOW" << endl;
		}
	
		loc = glGetUniformLocation(this->normalMappingNONSHADOWProgramHandle, "Tex1");
		if (loc>= 0 ){
			glUniform1i(loc, 0);
		} else {
			cerr << "Error al inicializar " << filename << " en Tex1 de normalMappingNONSHADOW" << endl;
		}
	}
}

void myWindow::initNormalMap(const char* filename){
	glActiveTexture(GL_TEXTURE2);
	glBindTexture(GL_TEXTURE_2D, textures[filename]);
	if (shadows){
		int loc = glGetUniformLocation(this->normalMappingProgramHandle, "normalMap");
		if (loc >= 0 ){
			glUniform1i(loc, 2);
		} else {
			cerr << "Error al inicializar " << filename << " en normalMap" << endl;
		}
	} else {
		int loc = glGetUniformLocation(this->normalMappingNONSHADOWProgramHandle, "normalMap");
		if (loc >= 0 ){
			glUniform1i(loc, 2);
		} else {
			cerr << "Error al inicializar " << filename << " en normalMap" << endl;
		}
	}
}

void myWindow::createCloth(int size)
{
    if (this->cloth_vertex_buffer != NULL)
    {
        delete this->cloth_vertex_buffer;
    }
    this->cloth_vertex_buffer_size = 12*(2*size +1);
    this->cloth_vertex_buffer = new GLfloat[this->cloth_vertex_buffer_size];
    
    
    if (this->cloth_index_buffer != NULL)
    {
        delete this->cloth_index_buffer;
    }
    this->cloth_index_buffer_size = 4*(2*size +1);
    this->cloth_index_buffer = new GLuint[this->cloth_index_buffer_size];

    int offset;
    for (int i=0; i<size; i++)
    {
        offset = 24*i;
        this->cloth_vertex_buffer[offset++] = -size;
        this->cloth_vertex_buffer[offset++] = i+1;
        this->cloth_vertex_buffer[offset++] = 0;

        this->cloth_vertex_buffer[offset++] = size;
        this->cloth_vertex_buffer[offset++] = i+1;
        this->cloth_vertex_buffer[offset++] = 0;

        this->cloth_vertex_buffer[offset++] = -size;
        this->cloth_vertex_buffer[offset++] = -(i+1);
        this->cloth_vertex_buffer[offset++] = 0;

        this->cloth_vertex_buffer[offset++] = size;
        this->cloth_vertex_buffer[offset++] = -(i+1);
        this->cloth_vertex_buffer[offset++] = 0;


        this->cloth_vertex_buffer[offset++] = i+1;
        this->cloth_vertex_buffer[offset++] = -size;
        this->cloth_vertex_buffer[offset++] = 0;

        this->cloth_vertex_buffer[offset++] = i+1;
        this->cloth_vertex_buffer[offset++] = size;
        this->cloth_vertex_buffer[offset++] = 0;

        this->cloth_vertex_buffer[offset++] = -(i+1);
        this->cloth_vertex_buffer[offset++] = -size;
        this->cloth_vertex_buffer[offset++] = 0;

        this->cloth_vertex_buffer[offset++] = -(i+1);
        this->cloth_vertex_buffer[offset++] = size;
        this->cloth_vertex_buffer[offset++] = 0;
    }

    offset = 24 * size;
    this->cloth_vertex_buffer[offset++]   = -size;
    this->cloth_vertex_buffer[offset++] = 0;
    this->cloth_vertex_buffer[offset++] = 0;

    this->cloth_vertex_buffer[offset++] = size;
    this->cloth_vertex_buffer[offset++] = 0;
    this->cloth_vertex_buffer[offset++] = 0;

    this->cloth_vertex_buffer[offset++] = 0;
    this->cloth_vertex_buffer[offset++] = -size;
    this->cloth_vertex_buffer[offset++] = 0;

    this->cloth_vertex_buffer[offset++] = 0;
    this->cloth_vertex_buffer[offset++] = size;
    this->cloth_vertex_buffer[offset++] = 0;

    for (int i=0; i< this->cloth_index_buffer_size; i++)
    {
        this->cloth_index_buffer[i] = i;
    }
}

void myWindow::createTriangleCloth()
{	
	int height = 1;
	int length = 160;
	int number_of_vertex = height*length;

    if (this->cloth_triangle_vertex_buffer != NULL)
    {
        delete this->cloth_triangle_vertex_buffer;
    }
    this->cloth_triangle_vertex_buffer_size = 3*number_of_vertex;
    this->cloth_triangle_vertex_buffer = new GLfloat[this->cloth_triangle_vertex_buffer_size];
    
    
    if (this->cloth_triangle_index_buffer != NULL)
    {
        delete this->cloth_triangle_index_buffer;
    }
    this->cloth_triangle_index_buffer_size = number_of_vertex;
    this->cloth_triangle_index_buffer = new GLuint[this->cloth_triangle_index_buffer_size];

	int i = 0;
	int j = 0;

	this->cloth_triangle_vertex_buffer[i++] = 0.0f;
	this->cloth_triangle_vertex_buffer[i++] = 0.0f;
	this->cloth_triangle_vertex_buffer[i++] = 0.0f;
	
	for (;i<3*(number_of_vertex-1);)
    {

        this->cloth_triangle_vertex_buffer[i++] = j++;
        this->cloth_triangle_vertex_buffer[i++] = 1;
        this->cloth_triangle_vertex_buffer[i++] = 0;

        this->cloth_triangle_vertex_buffer[i++] = j;
        this->cloth_triangle_vertex_buffer[i++] = 0;
        this->cloth_triangle_vertex_buffer[i++] = 0;

    }

    this->cloth_triangle_vertex_buffer[i++] = j;
    this->cloth_triangle_vertex_buffer[i++] = 1;
    this->cloth_triangle_vertex_buffer[i++] = 0;

	cout << "Max X = " + j << endl;

    for (int w=0; w < this->cloth_triangle_index_buffer_size; w++)
    {
        this->cloth_triangle_index_buffer[w] = w;
    }
}

void myWindow::createGrid(int size)
{
    if (this->grid_vertex_buffer != NULL)
    {
        delete this->grid_vertex_buffer;
    }
    this->grid_vertex_buffer_size = 12*(2*size +1);
    this->grid_vertex_buffer = new GLfloat[this->grid_vertex_buffer_size];
    
    
    if (this->grid_index_buffer != NULL)
    {
        delete this->grid_index_buffer;
    }
    this->grid_index_buffer_size = 4*(2*size +1);
    this->grid_index_buffer = new GLuint[this->grid_index_buffer_size];

    int offset;
    for (int i=0; i<size; i++)
    {
        offset = 24*i;
        this->grid_vertex_buffer[offset++] = -size;
        this->grid_vertex_buffer[offset++] = i+1;
        this->grid_vertex_buffer[offset++] = 0;

        this->grid_vertex_buffer[offset++] = size;
        this->grid_vertex_buffer[offset++] = i+1;
        this->grid_vertex_buffer[offset++] = 0;

        this->grid_vertex_buffer[offset++] = -size;
        this->grid_vertex_buffer[offset++] = -(i+1);
        this->grid_vertex_buffer[offset++] = 0;

        this->grid_vertex_buffer[offset++] = size;
        this->grid_vertex_buffer[offset++] = -(i+1);
        this->grid_vertex_buffer[offset++] = 0;


        this->grid_vertex_buffer[offset++] = i+1;
        this->grid_vertex_buffer[offset++] = -size;
        this->grid_vertex_buffer[offset++] = 0;

        this->grid_vertex_buffer[offset++] = i+1;
        this->grid_vertex_buffer[offset++] = size;
        this->grid_vertex_buffer[offset++] = 0;

        this->grid_vertex_buffer[offset++] = -(i+1);
        this->grid_vertex_buffer[offset++] = -size;
        this->grid_vertex_buffer[offset++] = 0;

        this->grid_vertex_buffer[offset++] = -(i+1);
        this->grid_vertex_buffer[offset++] = size;
        this->grid_vertex_buffer[offset++] = 0;
    }

    offset = 24 * size;
    this->grid_vertex_buffer[offset++]   = -size;
    this->grid_vertex_buffer[offset++] = 0;
    this->grid_vertex_buffer[offset++] = 0;

    this->grid_vertex_buffer[offset++] = size;
    this->grid_vertex_buffer[offset++] = 0;
    this->grid_vertex_buffer[offset++] = 0;

    this->grid_vertex_buffer[offset++] = 0;
    this->grid_vertex_buffer[offset++] = -size;
    this->grid_vertex_buffer[offset++] = 0;

    this->grid_vertex_buffer[offset++] = 0;
    this->grid_vertex_buffer[offset++] = size;
    this->grid_vertex_buffer[offset++] = 0;

    for (int i=0; i< this->grid_index_buffer_size; i++)
    {
        this->grid_index_buffer[i] = i;
    }
}

void myWindow::createSpiralSphere(const float radius, const unsigned int loops, const unsigned int segmentsPerLoop)
{
 
    if (this->vertex_buffer.size() >0)
    {
        this->vertex_buffer.clear();
    }

    if (this->index_buffer.size() >0)
    {
        this->index_buffer.clear();
    }

    float PI = 3.1415f;

    for (unsigned int loopSegmentNumber = 0; loopSegmentNumber < segmentsPerLoop; ++loopSegmentNumber)
    {
        float theta = 0;
        float phi = loopSegmentNumber * 2 * PI / segmentsPerLoop;
        float sinTheta = sin(theta);
        float sinPhi = sin(phi);
        float cosTheta = cos(theta);
        float cosPhi = cos(phi);

        // 
        this->vertex_buffer.push_back(radius * cosPhi * sinTheta); // Vx
        this->vertex_buffer.push_back(radius * sinPhi * sinTheta); // Vy
        this->vertex_buffer.push_back(radius * cosTheta);          // Vz
    }
    for (unsigned int loopNumber = 0; loopNumber <= loops; ++loopNumber)
    {
        for (unsigned int loopSegmentNumber = 0; loopSegmentNumber < segmentsPerLoop; ++loopSegmentNumber)
        {
            float theta = (loopNumber * PI / loops) + ((PI * loopSegmentNumber) / (segmentsPerLoop * loops));
            if (loopNumber == loops)
            {
                theta = PI;
            }
            float phi = loopSegmentNumber * 2 * PI / segmentsPerLoop;
            float sinTheta = sin(theta);
            float sinPhi = sin(phi);
            float cosTheta = cos(theta);
            float cosPhi = cos(phi);

            this->vertex_buffer.push_back(radius * cosPhi * sinTheta);
            this->vertex_buffer.push_back(radius * sinPhi * sinTheta);
            this->vertex_buffer.push_back(radius * cosTheta);
        }
    }
    for (unsigned int loopSegmentNumber = 0; loopSegmentNumber < segmentsPerLoop; ++loopSegmentNumber)
    {
        this->index_buffer.push_back(loopSegmentNumber);
        this->index_buffer.push_back(segmentsPerLoop + loopSegmentNumber);
    }
    for (unsigned int loopNumber = 0; loopNumber < loops; ++loopNumber)
    {
        for (unsigned int loopSegmentNumber = 0; loopSegmentNumber < segmentsPerLoop; ++loopSegmentNumber)
        {
            this->index_buffer.push_back(((loopNumber + 1) * segmentsPerLoop) + loopSegmentNumber);
            this->index_buffer.push_back(((loopNumber + 2) * segmentsPerLoop) + loopSegmentNumber);
        }
    }

    //
    if (this->sphere_vertex_buffer != NULL)
    {
        delete[] this->sphere_vertex_buffer;
    }
    this->sphere_vertex_buffer = new float[this->vertex_buffer.size()];
    
    if ( this->sphere_index_buffer != NULL)
    {
        delete[] this->sphere_index_buffer;
    }
    this->sphere_index_buffer = new unsigned int[this->index_buffer.size()];

    vector<float>::iterator vertex_it;
    unsigned int v = 0;
    for (vertex_it = this->vertex_buffer.begin(); vertex_it != this->vertex_buffer.end(); vertex_it++)
    {
        this->sphere_vertex_buffer[v] = *vertex_it;
        v++;
    }

    vector<unsigned int>::iterator index_it;
    unsigned int i = 0;
    for (index_it = this->index_buffer.begin(); index_it != this->index_buffer.end(); index_it++)
    {
        this->sphere_index_buffer[i] = *index_it;
        i++;
    }
}

float myWindow::degreesToRadians(float degrees) {
    return (degrees*M_PI)/180.0f;
}

void myWindow::createCylinder() {

    // Angle increment in degrees.
    float angleIncrement = 10.0f;
    float angleIncrementRadians;
    float currentAngle;
    float currentAngleRadians;

    // Position index.
    unsigned int i = 0;
    // Normal index.
    unsigned int j = 0;
	// Texture index.
	unsigned int u = 0;

    // 12 Triangles per cycle.
    this->cylinderPositionDataSize = (360*3*12)/angleIncrement;
    this->cylinderPositionData = new GLfloat[this->cylinderPositionDataSize];
    this->cylinderNormalDataSize = (360*3*12)/angleIncrement;
    this->cylinderNormalData = new GLfloat[this->cylinderNormalDataSize];
	this->cylinderTextureDataSize = (this->cylinderPositionDataSize/3) * 2;
	this->cylinderTextureData = new GLfloat[this->cylinderTextureDataSize];

    float height = 1.0f;
    float z = height/2;

    for( currentAngle = 0 ; currentAngle < 360 ; currentAngle+=angleIncrement ) {

        currentAngleRadians = degreesToRadians(currentAngle);
        angleIncrementRadians = degreesToRadians(angleIncrement);

        /* *** *
         * TOP *
         * *** */
        // Center vertex:
        this->cylinderPositionData[i++] = 0.0f;
        this->cylinderPositionData[i++] = 0.0f;
        this->cylinderPositionData[i++] = z;
        this->cylinderNormalData[j++] = 0.0f;
        this->cylinderNormalData[j++] = 0.0f;
        this->cylinderNormalData[j++] = 1.0f;
		this->cylinderTextureData[u++] = currentAngle/360;
		this->cylinderTextureData[u++] = 0.5 + z;

        
        // First outer vertex:
        this->cylinderPositionData[i++] = cos(currentAngleRadians);
        this->cylinderPositionData[i++] = sin(currentAngleRadians);
        this->cylinderPositionData[i++] = z;
        this->cylinderNormalData[j++] = 0.0f;
        this->cylinderNormalData[j++] = 0.0f;
        this->cylinderNormalData[j++] = 1.0f;
		this->cylinderTextureData[u++] = currentAngle/360;
		this->cylinderTextureData[u++] = 0.5 + z;

        // Second outer vertex:
        this->cylinderPositionData[i++] = cos(currentAngleRadians + angleIncrementRadians);
        this->cylinderPositionData[i++] = sin(currentAngleRadians + angleIncrementRadians);
        this->cylinderPositionData[i++] = z;
        this->cylinderNormalData[j++] = 0.0f;
        this->cylinderNormalData[j++] = 0.0f;
        this->cylinderNormalData[j++] = 1.0f;
		this->cylinderTextureData[u++] = (currentAngle + angleIncrement)/360;
		this->cylinderTextureData[u++] = 0.5 + z;

        /* **** *
         * BASE *
         * **** */
        // Center vertex:
        this->cylinderPositionData[i++] = 0.0f;
        this->cylinderPositionData[i++] = 0.0f;
        this->cylinderPositionData[i++] = -z;
        this->cylinderNormalData[j++] = 0.0f;
        this->cylinderNormalData[j++] = 0.0f;
        this->cylinderNormalData[j++] = -1.0f;
		this->cylinderTextureData[u++] = currentAngle/360;
		this->cylinderTextureData[u++] = 0.5 - z;

        
        // First outer vertex:
        this->cylinderPositionData[i++] = cos(currentAngleRadians);
        this->cylinderPositionData[i++] = sin(currentAngleRadians);
        this->cylinderPositionData[i++] = -z;
        this->cylinderNormalData[j++] = 0.0f;
        this->cylinderNormalData[j++] = 0.0f;
        this->cylinderNormalData[j++] = -1.0f;
		this->cylinderTextureData[u++] = currentAngle/360;
		this->cylinderTextureData[u++] = 0.5 - z;

        // Second outer vertex:
        this->cylinderPositionData[i++] = cos(currentAngleRadians + angleIncrementRadians);
        this->cylinderPositionData[i++] = sin(currentAngleRadians + angleIncrementRadians);
        this->cylinderPositionData[i++] = -z;
        this->cylinderNormalData[j++] = 0.0f;
        this->cylinderNormalData[j++] = 0.0f;
        this->cylinderNormalData[j++] = -1.0f;
		this->cylinderTextureData[u++] = (currentAngle+ angleIncrement)/360;
		this->cylinderTextureData[u++] = 0.5 - z;
        
        /* **** *
         * SIDE *
         * **** */
        this->cylinderPositionData[i++] = cos(currentAngleRadians);
        this->cylinderPositionData[i++] = sin(currentAngleRadians);
        this->cylinderPositionData[i++] = z;
        this->cylinderNormalData[j++] = cos(currentAngleRadians);
        this->cylinderNormalData[j++] = sin(currentAngleRadians);
        this->cylinderNormalData[j++] = 0.0f;
		this->cylinderTextureData[u++] = currentAngle/360;
		this->cylinderTextureData[u++] = 0.5 + z;
        
        this->cylinderPositionData[i++] = cos(currentAngleRadians + angleIncrementRadians);
        this->cylinderPositionData[i++] = sin(currentAngleRadians + angleIncrementRadians);
        this->cylinderPositionData[i++] = z;
        this->cylinderNormalData[j++] = cos(currentAngleRadians + angleIncrementRadians);
        this->cylinderNormalData[j++] = sin(currentAngleRadians + angleIncrementRadians);
        this->cylinderNormalData[j++] = 0.0f;
		this->cylinderTextureData[u++] = (currentAngle+ angleIncrement)/360;
		this->cylinderTextureData[u++] = 0.5 + z;

        this->cylinderPositionData[i++] = cos(currentAngleRadians);
        this->cylinderPositionData[i++] = sin(currentAngleRadians);
        this->cylinderPositionData[i++] = -z;
        this->cylinderNormalData[j++] = cos(currentAngleRadians);
        this->cylinderNormalData[j++] = sin(currentAngleRadians);
        this->cylinderNormalData[j++] = 0.0f;
		this->cylinderTextureData[u++] = currentAngle/360;
		this->cylinderTextureData[u++] = 0.5 - z;
        
        this->cylinderPositionData[i++] = cos(currentAngleRadians + angleIncrementRadians);
        this->cylinderPositionData[i++] = sin(currentAngleRadians + angleIncrementRadians);
        this->cylinderPositionData[i++] = z;
        this->cylinderNormalData[j++] = cos(currentAngleRadians + angleIncrementRadians);
        this->cylinderNormalData[j++] = sin(currentAngleRadians + angleIncrementRadians);
        this->cylinderNormalData[j++] = 0.0f;
		this->cylinderTextureData[u++] = (currentAngle+ angleIncrement)/360;
		this->cylinderTextureData[u++] = 0.5 - z;
        
        this->cylinderPositionData[i++] = cos(currentAngleRadians);
        this->cylinderPositionData[i++] = sin(currentAngleRadians);
        this->cylinderPositionData[i++] = -z;
        this->cylinderNormalData[j++] = cos(currentAngleRadians);
        this->cylinderNormalData[j++] = sin(currentAngleRadians);
        this->cylinderNormalData[j++] = 0.0f;
		this->cylinderTextureData[u++] = currentAngle/360;
		this->cylinderTextureData[u++] = 0.5 - z;
        
        this->cylinderPositionData[i++] = cos(currentAngleRadians + angleIncrementRadians);
        this->cylinderPositionData[i++] = sin(currentAngleRadians + angleIncrementRadians);
        this->cylinderPositionData[i++] = -z;
        this->cylinderNormalData[j++] = cos(currentAngleRadians + angleIncrementRadians);
        this->cylinderNormalData[j++] = sin(currentAngleRadians + angleIncrementRadians);
        this->cylinderNormalData[j++] = 0.0f;
		this->cylinderTextureData[u++] = (currentAngle + angleIncrement)/360;
		this->cylinderTextureData[u++] = 0.5 - z;

    }
}

void myWindow::renderGround(glm::mat4 model_matrix){

	// Normal Matrix
	glm::mat3 normal_matrix = glm::mat3(1.0f);
        
    // Bind Normal MAtrix
    GLuint location_normal_matrix = glGetUniformLocation( this->textureProgramHandle, "NormalMatrix"); 
    if( location_normal_matrix >= 0 ) 
    { 
        glUniformMatrix3fv( location_normal_matrix, 1, GL_FALSE, &normal_matrix[0][0]); 
    }

    // Bind Model Matrix
    GLuint location_model_matrix = glGetUniformLocation( this->textureProgramHandle, "ModelMatrix"); 
    if( location_model_matrix >= 0 ) 
    { 
        glUniformMatrix4fv( location_model_matrix, 1, GL_FALSE, &model_matrix[0][0]); 
    }

	 // Bind Normal MAtrix
    location_normal_matrix = glGetUniformLocation( this->textureNONSHADOWProgramHandle, "NormalMatrix"); 
    if( location_normal_matrix >= 0 ) 
    { 
        glUniformMatrix3fv( location_normal_matrix, 1, GL_FALSE, &normal_matrix[0][0]); 
    }

	 // Bind Model Matrix
    location_model_matrix = glGetUniformLocation( this->textureNONSHADOWProgramHandle, "ModelMatrix"); 
    if( location_model_matrix >= 0 ) 
    { 
        glUniformMatrix4fv( location_model_matrix, 1, GL_FALSE, &model_matrix[0][0]); 
    }

	// Bind Model Matrix to shadow program
	GLuint shadow_model_matrix = glGetUniformLocation( this->shadowProgramHandle, "ModelMatrix"); 
	if( location_model_matrix >= 0 ) 
	{ 
		glUniformMatrix4fv( shadow_model_matrix, 1, GL_FALSE, &model_matrix[0][0]); 
	}
	initTexture("textures/grass.png");

	glBegin(GL_QUADS);
	
		//Vertex 1
		glNormal3f(0,0,1);
		glTexCoord2f(30.0,30.0);
		glVertex3d(0.5,0.5,0);
		
		//Vertex 2
		glNormal3f(0,0,1);
		glTexCoord2f(0.0,30.0);
		glVertex3d(-0.5,0.5,0);
	
		//Vertex 3
		glNormal3f(0,0,1);
		glTexCoord2f(0.0,0.0);
		glVertex3d(-0.5,-0.5,0);
	
		//Vertex 4
		glNormal3f(0,0,1);
		glTexCoord2f(30.0,0.0);
		glVertex3d(0.5,-0.5,0);
		
	glEnd();
}

void myWindow::renderSpiralSphere(glm::mat4 model_matrix)
{
    // Normal Matrix
    glm::mat3 normal_matrix = inverse ( transpose (glm::mat3 ( model_matrix ) ) );

    // Bind Normal MAtrix
    GLuint location_normal_matrix = glGetUniformLocation( this->textureProgramHandle, "NormalMatrix"); 
    if( location_normal_matrix >= 0 ) 
    { 
        glUniformMatrix3fv( location_normal_matrix, 1, GL_FALSE, &normal_matrix[0][0]); 
    }

    // Bind Model Matrix
    GLuint location_model_matrix = glGetUniformLocation( this->textureProgramHandle, "ModelMatrix"); 
    if( location_model_matrix >= 0 ) 
    { 
        glUniformMatrix4fv( location_model_matrix, 1, GL_FALSE, &model_matrix[0][0]); 
    }

    glEnableClientState(GL_VERTEX_ARRAY);
    glEnableClientState(GL_NORMAL_ARRAY);

    glVertexPointer(3, GL_FLOAT, 0, sphere_vertex_buffer);
    glNormalPointer(GL_FLOAT, 0, sphere_vertex_buffer);

    glDrawElements(GL_TRIANGLE_STRIP, index_buffer.size(), GL_UNSIGNED_INT, sphere_index_buffer);

    glDisableClientState(GL_VERTEX_ARRAY);
    glDisableClientState(GL_NORMAL_ARRAY);
}

void myWindow::renderCube(glm::mat4 model_matrix,char* texture){
	if (shadows){
		glUseProgram(this->textureProgramHandle);
		if(firstPass)
			glUseProgram(this->shadowProgramHandle);
		renderCube(model_matrix,this->textureProgramHandle,1);
		glUseProgram(this->textureProgramHandle);
	} else {
		glUseProgram(this->textureNONSHADOWProgramHandle);
		renderCube(model_matrix,this->textureNONSHADOWProgramHandle,1);
		glUseProgram(this->textureNONSHADOWProgramHandle);
	}
	if (shadows) 
		if(firstPass) 
			glUseProgram(this->shadowProgramHandle);

}

void myWindow::renderCube(glm::mat4 model_matrix,GLuint programHandler, int textureRepetition)
{

    // Normal Matrix
	glm::mat3 normal_matrix = inverse ( transpose (glm::mat3 ( model_matrix ) ) );
        
    // Bind Normal MAtrix
    GLuint location_normal_matrix = glGetUniformLocation( programHandler, "NormalMatrix"); 
    if( location_normal_matrix >= 0 ) 
        glUniformMatrix3fv( location_normal_matrix, 1, GL_FALSE, &normal_matrix[0][0]); 

    // Bind Model Matrix
    GLuint location_model_matrix = glGetUniformLocation( programHandler, "ModelMatrix"); 
    if( location_model_matrix >= 0 ) 
        glUniformMatrix4fv( location_model_matrix, 1, GL_FALSE, &model_matrix[0][0]); 

	// Bind Model Matrix to shadow program
	GLuint shadow_model_matrix = glGetUniformLocation( this->shadowProgramHandle, "ModelMatrix"); 
	if( location_model_matrix >= 0 ) 
		glUniformMatrix4fv( shadow_model_matrix, 1, GL_FALSE, &model_matrix[0][0]); 

	//Frente
	glBegin(GL_QUADS);

	glNormal3f(1.0,0.0,0.0);
	glTexCoord2d((float)textureRepetition,0.0);
	glVertex3f(0.5,0.5,0.5);

	glNormal3f(1.0,0.0,0.0);
	glTexCoord2d((float)textureRepetition,(float)textureRepetition);
	glVertex3f(0.5,0.5,-0.5);

	glNormal3f(1.0,0.0,0.0);
	glTexCoord2d(0.0,(float)textureRepetition);
	glVertex3f(0.5,-0.5,-0.5);

	glNormal3f(1.0,0.0,0.0);
	glTexCoord2d(0.0,0.0);
	glVertex3f(0.5,-0.5,0.5);

	glEnd();

	//Top
	glBegin(GL_QUADS);

	glNormal3f(0.0,0.0,1.0);
	glTexCoord2d((float)textureRepetition,0.0);
	glVertex3f(0.5,0.5,0.5);

	glNormal3f(0.0,0.0,1.0);
	glTexCoord2d((float)textureRepetition,(float)textureRepetition);
	glVertex3f(-0.5,0.5,0.5);

	glNormal3f(0.0,0.0,1.0);
	glTexCoord2d(0.0,(float)textureRepetition);
	glVertex3f(-0.5,-0.5,0.5);

	glNormal3f(0.0,0.0,1.0);
	glTexCoord2d(0.0,0.0);
	glVertex3f(0.5,-0.5,0.5);

	glEnd();

	//Right
	glBegin(GL_QUADS);

	glNormal3f(0.0,1.0,0.0);
	glTexCoord2d((float)textureRepetition,0.0);
	glVertex3f(0.5,0.5,0.5);

	glNormal3f(0.0,1.0,0.0);
	glTexCoord2d((float)textureRepetition,(float)textureRepetition);
	glVertex3f(0.5,0.5,-0.5);

	glNormal3f(0.0,1.0,0.0);
	glTexCoord2d(0.0,(float)textureRepetition);
	glVertex3f(-0.5,0.5,-0.5);

	glNormal3f(0.0,1.0,0.0);
	glTexCoord2d(0.0,0.0);
	glVertex3f(-0.5,0.5,0.5);

	glEnd();

	//Back
	glBegin(GL_QUADS);

	glNormal3f(1.0,0.0,0.0);
	glTexCoord2d((float)textureRepetition,0.0);
	glVertex3f(-0.5,0.5,0.5);

	glNormal3f(1.0,0.0,0.0);
	glTexCoord2d((float)textureRepetition,(float)textureRepetition);
	glVertex3f(-0.5,0.5,-0.5);

	glNormal3f(1.0,0.0,0.0);
	glTexCoord2d(0.0,(float)textureRepetition);
	glVertex3f(-0.5,-0.5,-0.5);

	glNormal3f(1.0,0.0,0.0);
	glTexCoord2d(0.0,0.0);
	glVertex3f(-0.5,-0.5,0.5);

	glEnd();

	//Left
	glBegin(GL_QUADS);

	glNormal3f(0.0,1.0,0.0);
	glTexCoord2d((float)textureRepetition,0.0);
	glVertex3f(-0.5,-0.5,0.5);

	glNormal3f(0.0,1.0,0.0);
	glTexCoord2d((float)textureRepetition,(float)textureRepetition);
	glVertex3f(-0.5,-0.5,-0.5);

	glNormal3f(0.0,1.0,0.0);
	glTexCoord2d(0.0,(float)textureRepetition);
	glVertex3f(0.5,-0.5,-0.5);

	glNormal3f(0.0,1.0,0.0);
	glTexCoord2d(0.0,0.0);
	glVertex3f(0.5,-0.5,0.5);

	glEnd();

	//Bottom
	glBegin(GL_QUADS);

	glNormal3f(0.0,0.0,1.0);
	glTexCoord2d((float)textureRepetition,0.0);
	glVertex3f(0.5,0.5,-0.5);

	glNormal3f(0.0,0.0,1.0);
	glTexCoord2d((float)textureRepetition,(float)textureRepetition);
	glVertex3f(-0.5,0.5,-0.5);

	glNormal3f(0.0,0.0,1.0);
	glTexCoord2d(0.0,(float)textureRepetition);
	glVertex3f(-0.5,-0.5,-0.5);

	glNormal3f(0.0,0.0,1.0);
	glTexCoord2d(0.0,0.0);
	glVertex3f(0.5,-0.5,-0.5);

	glEnd();


}


void myWindow::renderCubeViejo(glm::mat4 model_matrix)
{
    // Normal Matrix
	glm::mat3 normal_matrix = inverse ( transpose (glm::mat3 ( model_matrix ) ) );
        
    // Bind Normal MAtrix
    GLuint location_normal_matrix = glGetUniformLocation( this->textureProgramHandle, "NormalMatrix"); 
    if( location_normal_matrix >= 0 ) 
    { 
        glUniformMatrix3fv( location_normal_matrix, 1, GL_FALSE, &normal_matrix[0][0]); 
    }

    // Bind Model Matrix
    GLuint location_model_matrix = glGetUniformLocation( this->textureProgramHandle, "ModelMatrix"); 
    if( location_model_matrix >= 0 ) 
    { 
        glUniformMatrix4fv( location_model_matrix, 1, GL_FALSE, &model_matrix[0][0]); 
    }



    glEnableClientState(GL_VERTEX_ARRAY);
    glEnableClientState(GL_NORMAL_ARRAY);

    glVertexPointer(3, GL_FLOAT, 0, cube_vertex_buffer);
    glNormalPointer(GL_FLOAT, 0, cube_normal_buffer);

    glDrawElements(GL_QUADS, this->cube_index_buffer_size, GL_UNSIGNED_INT, this->cube_index_buffer);

    glDisableClientState(GL_VERTEX_ARRAY);
    glDisableClientState(GL_NORMAL_ARRAY);
}

void configSkyBoxTexture(){
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
}
void myWindow::renderSkyBox(glm::mat4 model_matrix){

	glm::mat3 normal_matrix = glm::mat3(1.0f);
        
    GLuint location_normal_matrix = glGetUniformLocation( this->textureProgramHandle, "NormalMatrix"); 
    if( location_normal_matrix >= 0 ) 
        glUniformMatrix3fv( location_normal_matrix, 1, GL_FALSE, &normal_matrix[0][0]); 

    GLuint location_model_matrix = glGetUniformLocation( this->textureProgramHandle, "ModelMatrix"); 
    if( location_model_matrix >= 0 ) 
        glUniformMatrix4fv( location_model_matrix, 1, GL_FALSE, &model_matrix[0][0]); 

    location_normal_matrix = glGetUniformLocation( this->textureNONSHADOWProgramHandle, "NormalMatrix"); 
    if( location_normal_matrix >= 0 ) 
        glUniformMatrix3fv( location_normal_matrix, 1, GL_FALSE, &normal_matrix[0][0]); 

    location_model_matrix = glGetUniformLocation( this->textureNONSHADOWProgramHandle, "ModelMatrix"); 
    if( location_model_matrix >= 0 ) 
        glUniformMatrix4fv( location_model_matrix, 1, GL_FALSE, &model_matrix[0][0]); 


	initTexture("textures/skybox/otop18.jpg");
	configSkyBoxTexture();
	
	glUseProgram(textureNONSHADOWProgramHandle);
	glBegin(GL_QUADS);
		
		// CARA 1: base		
		//Vertex 1
		//glNormal3f(0,0,1);
		glTexCoord2f(1.0,1.0);
		glVertex3d(0.5,0.5,-0.5);
		
		//Vertex 2
		//glNormal3f(0,0,1);
		glTexCoord2f(0.0,1.0);
		glVertex3d(-0.5,0.5,-0.5);
	
		//Vertex 3
		//glNormal3f(0,0,1);
		glTexCoord2f(0.0,0.0);
		glVertex3d(-0.5,-0.5,-0.5);
	
		//Vertex 4
		//glNormal3f(0,0,1);
		glTexCoord2f(1.0,0.0);
		glVertex3d(0.5,-0.5,-0.5);

		// CARA 2: top	
		//Vertex 1
		glTexCoord2f(0.0,1.0);
		glVertex3d(0.5,0.5,0.5);
		
		//Vertex 2
		glTexCoord2f(0.0,0.0);
		glVertex3d(-0.5,0.5,0.5);

		//Vertex 3
		glTexCoord2f(1.0,0.0);
		glVertex3d(-0.5,-0.5,0.5);
	
		//Vertex 4
		glTexCoord2f(1.0,1.0);
		glVertex3d(0.5,-0.5,0.5);

	glEnd();
	
	initTexture("textures/skybox/ofront18.jpg");
	configSkyBoxTexture();
	glBegin(GL_QUADS);
		
		// CARA 3: front		
		//Vertex 1
		glTexCoord2f(0.0,0.0);
		glVertex3d(0.5,0.5,0.5);
		
		//Vertex 2
		glTexCoord2f(1.0,0.0);
		glVertex3d(0.5,-0.5,0.5);
	
		//Vertex 3
		glTexCoord2f(1.0,1.0);
		glVertex3d(0.5,-0.5,-0.5);
	
		//Vertex 4
		glTexCoord2f(0.0,1.0);
		glVertex3d(0.5,0.5,-0.5);

	glEnd();

	initTexture("textures/skybox/oback18.jpg");
	configSkyBoxTexture();
	glBegin(GL_QUADS);
		// CARA 4: back	
		//Vertex 1
		//glNormal3f(1,0,0);
		glTexCoord2f(1.0,0.0);
		glVertex3d(-0.5,0.5,0.5);
		
		//Vertex 2
		//glNormal3f(1,0,0);
		glTexCoord2f(0.0,0.0);
		glVertex3d(-0.5,-0.5,0.5);

	
		//Vertex 3
		//glNormal3f(1,0,0);
		glTexCoord2f(0.0,1.0);
		glVertex3d(-0.5,-0.5,-0.5);
	
		//Vertex 4
		//glNormal3f(1,0,0);
		glTexCoord2f(1.0,1.0);
		glVertex3d(-0.5,0.5,-0.5);

	glEnd();

	initTexture("textures/skybox/oleft18.jpg");
	configSkyBoxTexture();
	glBegin(GL_QUADS);
		
		// CARA 5: left		
		//Vertex 1
		glTexCoord2f(1.0,0.0);
		glVertex3d(0.5,0.5,0.5);
		
		//Vertex 2
		glTexCoord2f(0.0,0.0);
		glVertex3d(-0.5,0.5,0.5);

		//Vertex 3
		glTexCoord2f(0.0,1.0);
		glVertex3d(-0.5,0.5,-0.5);
	
		//Vertex 4
		glTexCoord2f(1.0,1.0);
		glVertex3d(0.5,0.5,-0.5);

	glEnd();
	
	initTexture("textures/skybox/oright18.jpg");
	configSkyBoxTexture();
	glBegin(GL_QUADS);
		// CARA 6: right	
		//Vertex 1
		glTexCoord2f(0.0,0.0);
		glVertex3d(0.5,-0.5,0.5);
		
		//Vertex 2
		glTexCoord2f(0.0,1.0);
		glVertex3d(0.5,-0.5,-0.5);
	
		//Vertex 3
		glTexCoord2f(1.0,1.0);
		glVertex3d(-0.5,-0.5,-0.5);
	
		//Vertex 4
		glTexCoord2f(1.0,0.0);
		glVertex3d(-0.5,-0.5,0.5);

	glEnd();

	glUseProgram(textureProgramHandle);
}


char* texMet = "textures/metalBrushed.png";
void myWindow::renderArm(glm::mat4 model_matrix)
{
    this->renderSpiralSphere(model_matrix);
    glm::mat4 m = glm::mat4 ( 1.0f );
    m = glm::scale(model_matrix, glm::vec3 (0.6f, 0.6f, 3.0f) );
    m = glm::translate(m , glm::vec3(0.0, 0.0, 0.5) );

    this->renderCube(m,texMet);
}

void myWindow::renderAltCylinder(glm::mat4 model_matrix,char* texture) {

	initTexture(texture);
	if (shadows){
		renderAltCylinder(model_matrix,this->textureProgramHandle,1);
	} else {
		renderAltCylinder(model_matrix,this->textureNONSHADOWProgramHandle,1);
	}

}

void myWindow::renderAltCylinder(glm::mat4 model_matrix,GLuint programHandler,int textureRepetition) {
	// Normal Matrix
	glm::mat3 normal_matrix = inverse ( transpose (glm::mat3 ( model_matrix ) ) );
       
	// Bind Normal MAtrix
	GLuint location_normal_matrix = glGetUniformLocation( programHandler, "NormalMatrix"); 
	if( location_normal_matrix >= 0 ) 
	{ 
		glUniformMatrix3fv( location_normal_matrix, 1, GL_FALSE, &normal_matrix[0][0]); 
	}
	 // Bind Model Matrix
	GLuint location_model_matrix = glGetUniformLocation( programHandler, "ModelMatrix"); 
	if( location_model_matrix >= 0 ) 
	{ 
		glUniformMatrix4fv( location_model_matrix, 1, GL_FALSE, &model_matrix[0][0]); 
	}

	// Bind Model Matrix to shadow program
	GLuint shadow_model_matrix = glGetUniformLocation( this->shadowProgramHandle, "ModelMatrix"); 
	if( location_model_matrix >= 0 ) 
	{ 
		glUniformMatrix4fv( shadow_model_matrix, 1, GL_FALSE, &model_matrix[0][0]); 
	}
	

	float paneHeight = 1.0f;
	float radius = 0.4f;
	float angleIncrement = 10.0f;
	float currentAngleRadians;
	float cosAngle;
	float sinAngle;

	glBegin(GL_QUAD_STRIP);
	for( float i = 0 ; i <= 360 + angleIncrement ; i+=angleIncrement ) {
		
        currentAngleRadians = degreesToRadians(i);
		cosAngle = radius*cos(currentAngleRadians);
		sinAngle = radius*sin(currentAngleRadians);

		glNormal3f(cosAngle, sinAngle,0.0f);
		glTexCoord2f(textureRepetition * (i/360), 0.0);
		glVertex3d(cosAngle, sinAngle, -paneHeight/2);

		glNormal3f(cosAngle, sinAngle,0.0f);
		glTexCoord2f(textureRepetition * (i/360), (float)textureRepetition);
		glVertex3d(cosAngle, sinAngle, paneHeight/2);
	}

	glEnd();
	glDisable(GL_BLEND);
}

void myWindow::renderCylinder(glm::mat4 model_matrix) {
	
	// Normal Matrix
    glm::mat3 normal_matrix = inverse ( transpose (glm::mat3 ( model_matrix ) ) );
	model_matrix = glm::scale(model_matrix, glm::vec3(0.5f,0.5f,1.0f));
        
    // Bind Normal MAtrix
    GLuint location_normal_matrix = glGetUniformLocation( this->textureProgramHandle, "NormalMatrix"); 
    if( location_normal_matrix >= 0 ) 
    { 
        glUniformMatrix3fv( location_normal_matrix, 1, GL_FALSE, &normal_matrix[0][0]); 
    }

	 // Bind Model Matrix
    GLuint location_model_matrix = glGetUniformLocation( this->textureProgramHandle, "ModelMatrix"); 
    if( location_model_matrix >= 0 ) 
    { 
        glUniformMatrix4fv( location_model_matrix, 1, GL_FALSE, &model_matrix[0][0]); 
    }


	     
    // Bind Normal MAtrix
    location_normal_matrix = glGetUniformLocation( this->textureNONSHADOWProgramHandle, "NormalMatrix"); 
    if( location_normal_matrix >= 0 ) 
    { 
        glUniformMatrix3fv( location_normal_matrix, 1, GL_FALSE, &normal_matrix[0][0]); 
    }

	 // Bind Model Matrix
    location_model_matrix = glGetUniformLocation( this->textureNONSHADOWProgramHandle, "ModelMatrix"); 
    if( location_model_matrix >= 0 ) 
    { 
        glUniformMatrix4fv( location_model_matrix, 1, GL_FALSE, &model_matrix[0][0]); 
    }


	// Bind Model Matrix to shadow program
	GLuint shadow_model_matrix = glGetUniformLocation( this->shadowProgramHandle, "ModelMatrix"); 
	if( location_model_matrix >= 0 ) 
	{ 
		glUniformMatrix4fv( shadow_model_matrix, 1, GL_FALSE, &model_matrix[0][0]); 
	}

	// Set the Tex1 sampler uniform to refer to texture unit 0
	int loc = glGetUniformLocation(this->textureProgramHandle, "Tex1");
    if( loc >= 0 )
    {
		// We indicate that Uniform Variable sampler2D "text" uses  Texture Unit 0 
        glUniform1i(loc, 0);
    }
    else
    {
        fprintf(stderr, "Uniform variable Tex1 not found!\n");
		cout << "Uniform variable Tex1 not found!" << endl;
	}

	// Falta bindear la normal matrix y la model matrix como esta hecho en el cubo.

    glEnableClientState(GL_VERTEX_ARRAY);
    glEnableClientState(GL_NORMAL_ARRAY);
    glEnableClientState(GL_TEXTURE_COORD_ARRAY);

    glNormalPointer(GL_FLOAT, 0, this->cylinderNormalData);
	glVertexPointer(3, GL_FLOAT, 0, this->cylinderPositionData);
	glTexCoordPointer(2, GL_FLOAT, 0,this->cylinderTextureData);
    
    glDrawArrays(GL_TRIANGLES, 0, this->cylinderPositionDataSize/3);
    
	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
    glDisableClientState(GL_VERTEX_ARRAY);
    glDisableClientState(GL_NORMAL_ARRAY);

}

void myWindow::renderCraneSection(glm::mat4 model_matrix)
{
	glm::mat4 m = glm::mat4 ( 1.0f );

	float escalaAncho = 0.2f, escalaLargo = 0.2f, escalaAltura= 3.0f;
	
	//Palito abajo
	m = glm::translate(model_matrix , glm::vec3(0.0, 0.0, -escalaAltura/2) );
	m = glm::rotate (m, 45.0f, glm::vec3(0.0, 1.0, 0.0));
	m = glm::rotate (m, 90.0f, glm::vec3(1.0, 0.0, 0.0));
	m = glm::scale(m, glm::vec3 (escalaAncho, escalaLargo, escalaAltura) );
    this->renderCube(m,texMet);

	glm::mat4 m2 = glm::mat4 ( 1.0f );
	//Palito arriba
    m2 = glm::translate(model_matrix , glm::vec3(0.0, 0.0, escalaAltura/2) );
	m2 = glm::rotate (m2, 45.0f, glm::vec3(0.0, 1.0, 0.0));
	m2 = glm::rotate (m2, 90.0f, glm::vec3(1.0, 0.0, 0.0));
	m2 = glm::scale(m2, glm::vec3 (escalaAncho, escalaLargo, escalaAltura) );
    this->renderCube(m2,texMet);

	glm::mat4 m3 = glm::mat4 ( 1.0f );
	//Palito derecha
    m3 = glm::translate(model_matrix , glm::vec3(0.0, escalaAltura/2 - escalaAncho/2, 0.0) );
	m3 = glm::rotate (m3, 45.0f, glm::vec3(0.0, 0.0, 1.0));
	m3 = glm::scale(m3, glm::vec3 (escalaAncho, escalaLargo, escalaAltura) );
    this->renderCube(m3,texMet);

	glm::mat4 m4 = glm::mat4 ( 1.0f );
	//Palito izq
    m4 = glm::translate(model_matrix , glm::vec3(0.0, -escalaAltura/2 + escalaAncho/2, 0.0) );
	m4 = glm::rotate (m4, 45.0f, glm::vec3(0.0, 0.0, 1.0));
	m4 = glm::scale(m4, glm::vec3 (escalaAncho, escalaLargo, escalaAltura) );
    this->renderCube(m4,texMet);

	glm::mat4 m5 = glm::mat4 ( 1.0f );
	
	//Palito diagonal
  
	//TODO - rotacion en el eje y de model matrix que no salio no se porq, rota en cualquier eje 
	
	m5 = glm::rotate (model_matrix, 45.0f, glm::vec3(0.0, 0.0, 1.0));
	m5 = glm::rotate (m5, 45.0f, glm::vec3(1.0, -1.0, 0.0));
	m5 = glm::scale(m5, glm::vec3 (escalaAncho, escalaLargo, sqrt(18.0)) );
    this->renderCube(m5,texMet);

}

void myWindow::renderCraneColumn(glm::mat4 model_matrix,int numberOfBlocks){
	float z=1.7;
	for(int i = 1 ; i <= numberOfBlocks ; i++) {
			glm::mat4 m = glm::mat4 ( 1.0f );
			m = glm::translate(model_matrix, glm::vec3(0.0,0.0,z));
			this->renderCraneBlock(m);
			z+=3.0;
		}
}

void myWindow::renderCraneBlock(glm::mat4 model_matrix)
{
	float largo = 3.0;
	
	//Atras
	glm::mat4 m = glm::mat4 ( 1.0f );
	m = glm::translate(model_matrix , glm::vec3(-largo/2,0.0,0.0) );
    this->renderCraneSection(m);

	//Adelante
	glm::mat4 m2 = glm::mat4 ( 1.0f );
	m2 = glm::translate(model_matrix , glm::vec3(largo/2,0.0,0.0) );
    this->renderCraneSection(m2);

	//izq
	glm::mat4 m3 = glm::mat4 ( 1.0f );
	
	m3 = glm::rotate (model_matrix, 90.0f, glm::vec3(0.0, 0.0, 1.0));
	m3 = glm::translate(m3 , glm::vec3(-1.5f,-largo/2 + 1.5f,0.0) );;
    this->renderCraneSection(m3);
   
	//der
	glm::mat4 m4 = glm::mat4 ( 1.0f );
	m4 = glm::rotate (model_matrix, -90.0f, glm::vec3(0.0, 0.0, 1.0));
	m4 = glm::translate(m4 , glm::vec3(-1.5f,largo/2 - 1.5f,0.0) );
    this->renderCraneSection(m4);
}

void myWindow::renderCraneCabin(glm::mat4 model_matrix,float height){

	model_matrix = glm::translate(model_matrix, glm::vec3(0.0f,0.0f,height + 2.5f));
	model_matrix = glm::scale(model_matrix,glm::vec3(8.0f,4.0f,5.0f));
	renderCube(model_matrix,texMet);

}

void myWindow::renderCraneArm(glm::mat4 model_matrix,int numberOfBlocks, float height){
	
	
	model_matrix = glm::translate(model_matrix, glm::vec3(4.0f,0.0f,height + 1.5f));
	model_matrix = glm::rotate(model_matrix, 90.0f, glm::vec3(0.0f,1.0f,0.0f));
	renderCraneColumn(model_matrix,numberOfBlocks);
}

void myWindow::renderCounterWeight(glm::mat4 model_matrix,int numberOfBlocks, float height){

	glm::mat4 m = model_matrix;
	m = glm::translate(m, glm::vec3(-4.0f - 3.0f*numberOfBlocks , 0.0f , height + 1.5f));
	m = glm::rotate(m, 90.0f, glm::vec3(0.0f,1.0f,0.0f));
	renderCraneColumn(m,numberOfBlocks);


	model_matrix = glm::translate(model_matrix, glm::vec3(-4.0f - 3.0f*numberOfBlocks - 1.25f , 0.0f , height + 2.0f));
	model_matrix = glm::scale(model_matrix,glm::vec3(3.0f,2.5f,6.0f));
	renderCube(model_matrix,texMet);
}

void myWindow::renderCrane(glm::mat4 model_matrix, int nColBlocks, int nArmBlocks, int nCounterWeightBlocks){

	changeObjectColor(1.0, 1.0, 1.0);
	model_matrix = glm::scale(model_matrix,glm::vec3(0.4f,0.4f,0.4f));
	renderCraneColumn(model_matrix,nColBlocks);
	model_matrix = glm::rotate(model_matrix,craneAngle,glm::vec3(0.0f,0.0f,1.0f));
	renderCraneCabin(model_matrix, nColBlocks*3.0f);
	renderCraneArm(model_matrix,nArmBlocks,nColBlocks*3.0f);
	renderCounterWeight(model_matrix,nCounterWeightBlocks,nColBlocks*3.0f);

}

char* texAsf = "textures/asphalt.png";

void myWindow::renderAltSlab(glm::mat4 model_matrix,bool firstPass) {

	GLuint programHandler;

	if (shadows){
		programHandler = normalMappingProgramHandle;
		glUseProgram(this->normalMappingProgramHandle);
	} else {
		programHandler = normalMappingNONSHADOWProgramHandle;
		glUseProgram(this->normalMappingNONSHADOWProgramHandle);
	}


	// Normal Matrix
	glm::mat3 normal_matrix = inverse ( transpose (glm::mat3 ( model_matrix ) ) );

	// Bind Normal MAtrix

	GLuint location_normal_matrix = glGetUniformLocation( programHandler, "NormalMatrix"); 
	if( location_normal_matrix >= 0 ) 
		glUniformMatrix3fv( location_normal_matrix, 1, GL_FALSE, &normal_matrix[0][0]); 

	// Bind Model Matrix
	GLuint location_model_matrix = glGetUniformLocation( programHandler, "ModelMatrix"); 
	if( location_model_matrix >= 0 ) 
		glUniformMatrix4fv( location_model_matrix, 1, GL_FALSE, &model_matrix[0][0]); 


	// Bind Model Matrix to shadow program
	if (shadows && firstPass)
		glUseProgram(this->shadowProgramHandle);
	GLuint shadow_model_matrix = glGetUniformLocation( this->shadowProgramHandle, "ModelMatrix"); 
	if( location_model_matrix >= 0 ) 
		glUniformMatrix4fv( shadow_model_matrix, 1, GL_FALSE, &model_matrix[0][0]); 

	float slabHeight = 0.25f;



	/* 
	*  Posiciones donde irian las columnas (con un offset hacia 'adentro'):
	* (-3, 1)		w	(0, 1)		(2, 1)
	*
	*					(0,-1)		(2,-1)
	* (-3,-2)			(0,-2)
	*/

	/* Vertices del cuadrado hueco (limite de las bases de las escaleras)
	* (0.5, 0.9)		(1.5, 0.9)
	*
	* (0.5,-0.1)		(1.5,-0.1)
	*/

	// Cara superior
	initTexture("textures/floor.png");
	initNormalMap("textures/floor-normalmap.png");

	
	glBegin(GL_TRIANGLE_STRIP);
	for(unsigned x = 0 ; x < 22 ; x++ )
		glNormal3f(0.0f, 0.0f, 1.0f);
	glTexCoord2f(-3.0, -2.0);
	glVertex3d(-3.0, -2.0, slabHeight/2);
	glTexCoord2f(-3.0, 1.0);
	glVertex3d(-3.0, 1.0 , slabHeight/2);
	glTexCoord2f(0.0 , -2.0);
	glVertex3d(0.0 , -2.0, slabHeight/2);
	glTexCoord2f(0.0 , 1.0);
	glVertex3d(0.0 , 1.0 , slabHeight/2);
	glTexCoord2f(0.0 , -0.1);
	glVertex3d(0.0 , -0.1, slabHeight/2);
	glTexCoord2f(0.5 , 1.0);
	glVertex3d(0.5 , 1.0 , slabHeight/2);
	glTexCoord2f(0.5 , -0.1);
	glVertex3d(0.5 , -0.1, slabHeight/2);
	glTexCoord2f(0.0 , -0.1);
	glVertex3d(0.0 , -0.1, slabHeight/2);
	glTexCoord2f(0.5 , -1.0);
	glVertex3d(0.5 , -1.0, slabHeight/2);
	glTexCoord2f(0.0 , -1.0);
	glVertex3d(0.0 , -1.0, slabHeight/2);
	glTexCoord2f(2.0 , -1.0);
	glVertex3d(2.0 , -1.0, slabHeight/2);
	glTexCoord2f(0.5 , -1.0);
	glVertex3d(0.5 , -1.0, slabHeight/2);
	glTexCoord2f(2.0 , -0.1);
	glVertex3d(2.0 , -0.1, slabHeight/2);
	glTexCoord2f(0.5 , -0.1);
	glVertex3d(0.5 , -0.1, slabHeight/2);
	glTexCoord2f(1.5 , -0.1);
	glVertex3d(1.5 , -0.1, slabHeight/2);
	glTexCoord2f(2.0 , -0.1);
	glVertex3d(2.0 , -0.1, slabHeight/2);
	glTexCoord2f(2.0 , 1.0);
	glVertex3d(2.0 , 1.0 , slabHeight/2);
	glTexCoord2f(1.5 , -0.1);
	glVertex3d(1.5 , -0.1, slabHeight/2);
	glTexCoord2f(1.5 , 1.0);
	glVertex3d(1.5 , 1.0 , slabHeight/2);
	glTexCoord2f(1.5 , 0.9);
	glVertex3d(1.5 , 0.9 , slabHeight/2);
	glTexCoord2f(0.5 , 1.0);
	glVertex3d(0.5 , 1.0 , slabHeight/2);
	glTexCoord2f(0.5,0.9);
	glVertex3d(0.5 , 0.9 , slabHeight/2);
	glEnd();

	if (shadows){
		programHandler = textureProgramHandle;
		glUseProgram(this->textureProgramHandle);
	} else {
		programHandler = textureNONSHADOWProgramHandle;
		glUseProgram(this->textureNONSHADOWProgramHandle);
	}



	// Bind Normal MAtrix

	location_normal_matrix = glGetUniformLocation( programHandler, "NormalMatrix"); 
	if( location_normal_matrix >= 0 ) 
		glUniformMatrix3fv( location_normal_matrix, 1, GL_FALSE, &normal_matrix[0][0]); 

	// Bind Model Matrix
	location_model_matrix = glGetUniformLocation( programHandler, "ModelMatrix"); 
	if( location_model_matrix >= 0 ) 
		glUniformMatrix4fv( location_model_matrix, 1, GL_FALSE, &model_matrix[0][0]); 

	if (shadows && firstPass){
		glUseProgram(this->shadowProgramHandle);
	}

	// Cara inferior
	glBegin(GL_TRIANGLE_STRIP);
	for(unsigned y = 0 ; y < 22 ; y++ )
		glNormal3f(0.0f, 0.0f, -1.0f);
	glTexCoord2f(-3.0, -2.0);
	glVertex3d(-3.0, -2.0, -slabHeight/2);
	glTexCoord2f(-3.0, 1.0);
	glVertex3d(-3.0, 1.0 , -slabHeight/2);
	glTexCoord2f(0.0 , -2.0);
	glVertex3d(0.0 , -2.0, -slabHeight/2);
	glTexCoord2f(0.0 , 1.0);
	glVertex3d(0.0 , 1.0 , -slabHeight/2);
	glTexCoord2f(0.0 , -0.1);
	glVertex3d(0.0 , -0.1, -slabHeight/2);
	glTexCoord2f(0.5 , 1.0);
	glVertex3d(0.5 , 1.0 , -slabHeight/2);
	glTexCoord2f(0.5 , -0.1);
	glVertex3d(0.5 , -0.1, -slabHeight/2);
	glTexCoord2f(0.0 , -0.1);
	glVertex3d(0.0 , -0.1, -slabHeight/2);
	glTexCoord2f(0.5 , -1.0);
	glVertex3d(0.5 , -1.0, -slabHeight/2);
	glTexCoord2f(0.0 , -1.0);
	glVertex3d(0.0 , -1.0, -slabHeight/2);
	glTexCoord2f(2.0 , -1.0);
	glVertex3d(2.0 , -1.0, -slabHeight/2);
	glTexCoord2f(0.5 , -1.0);
	glVertex3d(0.5 , -1.0, -slabHeight/2);
	glTexCoord2f(2.0 , -0.1);
	glVertex3d(2.0 , -0.1, -slabHeight/2);
	glTexCoord2f(0.5 , -0.1);
	glVertex3d(0.5 , -0.1, -slabHeight/2);
	glTexCoord2f(1.5 , -0.1);
	glVertex3d(1.5 , -0.1, -slabHeight/2);
	glTexCoord2f(2.0 , -0.1);
	glVertex3d(2.0 , -0.1, -slabHeight/2);
	glTexCoord2f(2.0 , 1.0);
	glVertex3d(2.0 , 1.0 , -slabHeight/2);
	glTexCoord2f(1.5 , -0.1);
	glVertex3d(1.5 , -0.1, -slabHeight/2);
	glTexCoord2f(1.5 , 1.0);
	glVertex3d(1.5 , 1.0 , -slabHeight/2);
	glTexCoord2f(1.5 , 0.9);
	glVertex3d(1.5 , 0.9 , -slabHeight/2);
	glTexCoord2f(0.5 , 1.0);
	glVertex3d(0.5 , 1.0 , -slabHeight/2);
	glTexCoord2f(0.5,0.9);
	glVertex3d(0.5 , 0.9 , -slabHeight/2);
	glEnd();

	// Borde externo
	glBegin(GL_QUAD_STRIP);
	for(unsigned z = 0 ; z < 4 ; z++ )
		glNormal3f(-1.0f, 0.0f, 0.0f);
	glTexCoord2f(0.0,0.0);
	glVertex3d(-3.0, 1.0 , slabHeight/2);
	glTexCoord2f(0.0,0.0);
	glVertex3d(-3.0, 1.0 , -slabHeight/2);
	glTexCoord2f(0.0,0.0);
	glVertex3d(-3.0, -2.0 , slabHeight/2);
	glTexCoord2f(0.0,0.0);
	glVertex3d(-3.0, -2.0 , -slabHeight/2);
	for(unsigned z = 0 ; z < 2 ; z++ )
		glNormal3f(0.0f, -1.0f, 0.0f);
	glTexCoord2f(0.0,0.0);
	glVertex3d(0.0, -2.0 , slabHeight/2);
	glTexCoord2f(0.0,0.0);
	glVertex3d(0.0, -2.0 , -slabHeight/2);
	for(unsigned z = 0 ; z < 2 ; z++ )
		glNormal3f(1.0f, 0.0f, 0.0f);
	glTexCoord2f(0.0,0.0);
	glVertex3d(0.0, -1.0 , slabHeight/2);
	glTexCoord2f(0.0,0.0);
	glVertex3d(0.0, -1.0 , -slabHeight/2);
	for(unsigned z = 0 ; z < 2 ; z++ )
		glNormal3f(0.0f, -1.0f, 0.0f);
	glTexCoord2f(0.0,0.0);
	glVertex3d(2.0, -1.0 , slabHeight/2);
	glTexCoord2f(0.0,0.0);
	glVertex3d(2.0, -1.0 , -slabHeight/2);
	for(unsigned z = 0 ; z < 2 ; z++ )
		glNormal3f(1.0f, 0.0f, 0.0f);
	glTexCoord2f(0.0,0.0);
	glVertex3d(2.0, 1.0 , slabHeight/2);
	glTexCoord2f(0.0,0.0);
	glVertex3d(2.0, 1.0 , -slabHeight/2);
	for(unsigned z = 0 ; z < 2 ; z++ )
		glNormal3f(0.0f, 1.0f, 0.0f);
	glTexCoord2f(0.0,0.0);
	glVertex3d(-3.0, 1.0 , slabHeight/2);
	glTexCoord2f(0.0,0.0);
	glVertex3d(-3.0, 1.0 , -slabHeight/2);
	glEnd();

	// Borde interno
	glBegin(GL_QUAD_STRIP);
	for(unsigned z = 0 ; z < 4 ; z++ )
		glNormal3f(0.0f, -1.0f, 0.0f);
	glTexCoord2f(0.0,0.0);
	glVertex3d(0.5,  0.9 , slabHeight/2);
	glTexCoord2f(0.0,0.0);
	glVertex3d(0.5,  0.9 , -slabHeight/2);
	glTexCoord2f(0.0,0.0);
	glVertex3d(1.5,  0.9 , slabHeight/2);
	glTexCoord2f(0.0,0.0);
	glVertex3d(1.5,  0.9 , -slabHeight/2);
	for(unsigned z = 0 ; z < 2 ; z++ )
		glNormal3f(-1.0f, 0.0f, 0.0f);
	glTexCoord2f(0.0,0.0);
	glVertex3d(1.5,  -0.1 , slabHeight/2);
	glTexCoord2f(0.0,0.0);
	glVertex3d(1.5,  -0.1 , -slabHeight/2);
	for(unsigned z = 0 ; z < 2 ; z++ )
		glNormal3f(0.0f, 1.0f, 0.0f);
	glTexCoord2f(0.0,0.0);
	glVertex3d(0.5,  -0.1 , slabHeight/2);
	glTexCoord2f(0.0,0.0);
	glVertex3d(0.5,  -0.1 , -slabHeight/2);
	for(unsigned z = 0 ; z < 2 ; z++ )
		glNormal3f(1.0f, 1.0f, 0.0f);
	glTexCoord2f(0.0,0.0);
	glVertex3d(0.5,  0.9 , slabHeight/2);
	glTexCoord2f(0.0,0.0);
	glVertex3d(0.5,  0.9 , -slabHeight/2);
	glEnd();



}

float mirrorOffsetH = 0.0;
float mirrorOffsetV = 0.0;

void myWindow::renderPane(glm::mat4 model_matrix, bool transparent) {
	
	if (firstPass) return;
	if(transparent) { 
		glEnable(GL_BLEND);
		glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	} else {
		glEnable(GL_CULL_FACE);
	}

	// Normal Matrix
	glm::mat3 normal_matrix = inverse ( transpose (glm::mat3 ( model_matrix ) ) );
       
	// Bind Normal MAtrix
	GLuint location_normal_matrix = glGetUniformLocation( this->textureProgramHandle, "NormalMatrix"); 
	if( location_normal_matrix >= 0 ) 
	{ 
		glUniformMatrix3fv( location_normal_matrix, 1, GL_FALSE, &normal_matrix[0][0]); 
	}
	 // Bind Model Matrix
	GLuint location_model_matrix = glGetUniformLocation( this->textureProgramHandle, "ModelMatrix"); 
	if( location_model_matrix >= 0 ) 
	{ 
		glUniformMatrix4fv( location_model_matrix, 1, GL_FALSE, &model_matrix[0][0]); 
	}

	// Bind Normal MAtrix
    location_normal_matrix = glGetUniformLocation( this->textureNONSHADOWProgramHandle, "NormalMatrix"); 
    if( location_normal_matrix >= 0 ) 
    { 
        glUniformMatrix3fv( location_normal_matrix, 1, GL_FALSE, &normal_matrix[0][0]); 
    }

	 // Bind Model Matrix
    location_model_matrix = glGetUniformLocation( this->textureNONSHADOWProgramHandle, "ModelMatrix"); 
    if( location_model_matrix >= 0 ) 
    { 
        glUniformMatrix4fv( location_model_matrix, 1, GL_FALSE, &model_matrix[0][0]); 
    }
	
	// Bind Model Matrix to shadow program
	GLuint shadow_model_matrix = glGetUniformLocation( this->shadowProgramHandle, "ModelMatrix"); 
	if( location_model_matrix >= 0 ) 
	{ 
		glUniformMatrix4fv( shadow_model_matrix, 1, GL_FALSE, &model_matrix[0][0]); 
	}

	float paneHeight = 2.0f;
	float paneWidth = 0.9f;
	float numberOfPanes = 10.5;
	int constant = 120;
	initTexture("textures/reflection.jpg");

	glBegin(GL_QUADS);
	 
	float ammountUsed = 0.4;
	float c=1.0;
	glNormal3f(0.0f,1.0f,0.0f);
	glTexCoord2f((0.0f + mirrorOffsetH)/(mirrorOffsetH+c),(ammountUsed+mirrorOffsetV)/(mirrorOffsetV+c));
	glVertex3d(0.0f, 0.0f, 0.0f);
	 
	glNormal3f(0.0f,1.0f,0.0f);
	glTexCoord2f((0.0f + mirrorOffsetH)/(mirrorOffsetH+c),(0.0f+mirrorOffsetV)/(mirrorOffsetV+c));
	glVertex3d(0.0f, 0.0f, numberOfPanes*paneHeight);

	glNormal3f(0.0f,1.0f,0.0f);
	glTexCoord2f((ammountUsed + mirrorOffsetH)/(mirrorOffsetH+c),(0.0f+mirrorOffsetV)/(mirrorOffsetV+c));
	glVertex3d(numberOfPanes*paneWidth, 0.0f, numberOfPanes*paneHeight);

	glNormal3f(0.0f,1.0f,0.0f);
	glTexCoord2f((ammountUsed + mirrorOffsetH)/(mirrorOffsetH+c),(ammountUsed+mirrorOffsetV)/(mirrorOffsetV+c));
	glVertex3d(numberOfPanes*paneWidth, 0.0f, 0.0);

	glEnd();
	
	if (transparent) {
		glDisable (GL_BLEND);
	} else {
	
	glDisable (GL_CULL_FACE);
	
	float offsetX = 0.0f;
	float offsetY = 0.1f;
	float borderSpace = (paneWidth * numberOfPanes)/5;
	float borderWidth = 0.2f;
	
	initTexture("textures/brushedmetal.png");
	while( offsetX <= paneWidth * numberOfPanes + 1 ) {
		glm::mat4 cubeMatrix = glm::translate(model_matrix, glm::vec3(offsetX,0.0,numberOfPanes*paneHeight/2));
		cubeMatrix = glm::scale(cubeMatrix,glm::vec3(borderWidth,borderWidth,numberOfPanes*paneHeight));
		renderCube(cubeMatrix, "textures/brushedmetal.png");
		offsetX += borderSpace;
	}

	float offsetZ = 0.0;
	float borderSpaceZ = paneHeight * numberOfPanes / 9;

	while( offsetZ <= paneHeight * numberOfPanes + 1 ) {
		glm::mat4 cubeMatrix = glm::translate(model_matrix, glm::vec3(numberOfPanes*paneWidth/2,0.0,offsetZ));
		cubeMatrix = glm::scale(cubeMatrix,glm::vec3(numberOfPanes*paneWidth,borderWidth,borderWidth));
		renderCube(cubeMatrix, "textures/brushedmetal.png");

		offsetZ += borderSpaceZ;
	}
	}

	glUseProgram(textureNONSHADOWProgramHandle);

}

void myWindow::renderWall(glm::mat4 model_matrix,bool firstPass){

	if (shadows)
		glUseProgram(this->normalMappingProgramHandle);
	else 
		glUseProgram(this->normalMappingNONSHADOWProgramHandle);
	
	model_matrix = glm::translate(model_matrix,glm::vec3(0.0f, -0.05f, 0.4725f) );
	model_matrix = glm::scale(model_matrix, glm::vec3(2.0f, 0.1f, 0.945f) );
	initTexture("textures/brick.jpg");
	initNormalMap("textures/brick-normalmap.png");
	
	if (shadows)
		if(firstPass) 
			glUseProgram(this->shadowProgramHandle);
	if (shadows){
		renderCube(model_matrix,this->normalMappingProgramHandle,2);
		glUseProgram(this->textureProgramHandle);
	} else {
		renderCube(model_matrix,this->normalMappingNONSHADOWProgramHandle,2);
		glUseProgram(this->textureNONSHADOWProgramHandle);
	}
	if (shadows) 
		if(firstPass) 
			glUseProgram(this->shadowProgramHandle);

}

void myWindow::renderStairs(glm::mat4 model_matrix){

	initTexture("textures/wood.png");

	changeObjectColor(0.824f,0.824f,0.824f);
	glm::mat4 m = glm::mat4 ( 1.0f );
	unsigned int numberOfStairs = 10;
	
	float quadWidth = 0.5f;
	float quadLength = 0.5f;
	float quadHeight = 0.1f;
	float x = 0.0f;
	float y = 0.0f;
	float z = 0.0f;
	m = glm::translate(model_matrix, glm::vec3(x,y,z));
	m = glm::scale(m, glm::vec3 (quadWidth, quadLength, quadHeight) );
    this->renderCube(m,"textures/wood.png");
	
	m = glm::mat4 ( 1.0f );
	quadWidth = 0.1f;
	quadLength = 0.5f;
	quadHeight = 0.1f;
	x = 0.3f;
	y = 0.0f;
	z = 0.1f;
	m = glm::translate(model_matrix, glm::vec3(x,y,z));
	m = glm::scale(m, glm::vec3 (quadWidth, quadLength, quadHeight) );
    this->renderCube(m,"textures/wood.png");
	
	for( unsigned int i = 0 ; i < numberOfStairs - 1 ; i++ ) {

		m = glm::mat4 ( 1.0f );
		x += 0.1f;
		z += 0.1f;
		m = glm::translate(model_matrix, glm::vec3(x,y,z));
		m = glm::scale(m, glm::vec3 (quadWidth, quadLength, quadHeight) );
		this->renderCube(m,"textures/wood.png");
	
	}
	
	m = glm::mat4 ( 1.0f );
	quadWidth = 0.5f;
	quadLength = 0.5f;
	quadHeight = 0.1f;
	x += 0.3f;
	z += 0.1f;
	m = glm::translate(model_matrix, glm::vec3(x,y,z));
	m = glm::scale(m, glm::vec3 (quadWidth, quadLength, quadHeight) );
    this->renderCube(m,"textures/wood.png");

}

void myWindow::renderColumn(glm::mat4 model_matrix,bool firstPass){

	float height = 3.0f;
	
	model_matrix = glm::translate(model_matrix, glm::vec3(0.0f,0.0f,height/2));
	model_matrix = glm::scale(model_matrix,glm::vec3(1.0f, 1.0f, height));
	
	if (shadows){
		glUseProgram(normalMappingProgramHandle);
	} else {
		glUseProgram(normalMappingNONSHADOWProgramHandle);
	}

	initTexture("textures/marble.png");
	initNormalMap("textures/marble-normalmap.png");

	if(shadows && firstPass) 
		glUseProgram(this->shadowProgramHandle);

	if (shadows){
		renderAltCylinder(model_matrix, normalMappingProgramHandle,4);
		glUseProgram(textureProgramHandle);
	} else {
		renderAltCylinder(model_matrix, normalMappingNONSHADOWProgramHandle,4);
		glUseProgram(textureNONSHADOWProgramHandle);
	}

	if(shadows && firstPass) 
		glUseProgram(this->shadowProgramHandle);

}

void myWindow::renderFloor(glm::mat4 model_matrix, bool pair,bool firstPass){
	if (shadows && firstPass)
		glUseProgram(this->shadowFragShader);
	


	glm::mat4 m = glm::scale(model_matrix,glm::vec3(3.0f,3.0f,1.0f));
	renderAltSlab(m, firstPass);

	if (!pair){
		m = glm::translate(model_matrix, glm::vec3(1.89f, 0.3f, 0.05f));
		m = glm::scale(m,glm::vec3(1.5f, 2.5f, 1.5f));
		renderStairs(m);
	} else {
		m = glm::translate(model_matrix, glm::vec3(4.13f, 2.09f, 0.05f));
		m = glm::scale(m,glm::vec3(1.5f, 2.5f, 1.5f));
		m = glm::rotate(m, 180.0f ,glm::vec3(0.0f, 0.0f, 1.0f));
		renderStairs(m);
	}

	m = glm::translate(model_matrix, glm::vec3(-1.0,-1.0f,1.4));
	m = glm::rotate(m, 90.0f, glm::vec3(0.0,0.0,1.0));
	m = glm::scale(m, glm::vec3(0.3,0.3,0.3));
	renderSweepSurface(m);

	m = glm::translate(model_matrix, glm::vec3(1.89f, 3.0f, 0.15f));
	m = glm::scale(m,glm::vec3(1.0f, 1.0f, 0.7f));

	float scaleX = 0.5f;
	float scaleY = 0.5f;
	float scaleZ = 0.55f;

	//Columna 1
	m = glm::translate(model_matrix, glm::vec3(5.4f, 2.6f, 0.0f));
	m = glm::scale(m,glm::vec3(scaleX,scaleY,scaleZ));
	renderColumn(m,firstPass);

	//Columna 2
	m = glm::translate(model_matrix, glm::vec3(5.4f, -2.6f, 0.0f));
	m = glm::scale(m,glm::vec3(scaleX,scaleY,scaleZ));
	renderColumn(m,firstPass);

	//Columna 3
	m = glm::translate(model_matrix, glm::vec3(-0.4f, 2.6f, 0.0f));
	m = glm::scale(m,glm::vec3(scaleX,scaleY,scaleZ));
	renderColumn(m,firstPass);

	//Columna 4
	m = glm::translate(model_matrix, glm::vec3(-0.4f, -5.5f, 0.0f));
	m = glm::scale(m,glm::vec3(scaleX,scaleY,scaleZ));
	renderColumn(m,firstPass);

	//Columna 5
	m = glm::translate(model_matrix, glm::vec3(-8.7f, 2.6f, 0.0f));
	m = glm::scale(m,glm::vec3(scaleX,scaleY,scaleZ));
	renderColumn(m,firstPass);

	//Columna 6
	m = glm::translate(model_matrix, glm::vec3(-8.7f, -5.5f, 0.0f));
	m = glm::scale(m,glm::vec3(scaleX,scaleY,scaleZ));
	renderColumn(m,firstPass);
}

void myWindow::renderBuilding(glm::mat4 model_matrix, int nFloors,bool firstPass){

	float z = 0.0f;
	
	for (int i = 0 ; i < nFloors ; i++){

		glm::mat4 m = glm::translate(model_matrix, glm::vec3(0.0f,0.0f,z));
		renderFloor(m, (i % 2 == 0), firstPass );
		glm::mat4 m2 = glm::translate(model_matrix, glm::vec3(4.00f, 3.01f, z + 0.10f));
		m2 = glm::scale(m2,glm::vec3(2.0f, 1.0f, 1.5f));
		renderWall(m2,firstPass);
		glm::mat4 m3 = glm::translate(m2, glm::vec3(-2.00f, 0.0, 0.0));
		renderWall(m3,firstPass);

		z += (3.0f*0.55);
	}
	
	glm::mat4 m = glm::translate(model_matrix, glm::vec3(0.0f,0.0f,z));
	m = glm::scale(m,glm::vec3(3.0f,3.0f,1.0f));
	
	renderAltSlab(m, firstPass);

	m = glm::translate(model_matrix, glm::vec3(-4.00f, 3.01f, 0.15f));
	m = glm::scale(m,glm::vec3(0.5f, 1.0f, 0.71f));
}

const char* loadShaderAsString(const char* file)
{
    ifstream shader_file(file, ifstream::in);
    string str((istreambuf_iterator<char>(shader_file)), istreambuf_iterator<char>());
    return str.c_str();
}

myWindow::myWindow()
{
    this->sphere_vertex_buffer = NULL;
    this->sphere_index_buffer = NULL;
    this->grid_index_buffer = NULL;
    this->grid_vertex_buffer = NULL;
    this->cloth_index_buffer = NULL;
    this->cloth_vertex_buffer = NULL;
    this->cube_index_buffer = NULL;
    this->cube_vertex_buffer = NULL;
    this->cube_normal_buffer = NULL;
	this->cloth_triangle_vertex_buffer = NULL;
	this->cloth_triangle_index_buffer = NULL;
	this->craneAngle = 0;
	this->craneAngleSpeed = 0.0f;
	nTrees = 0;
	lastAdded = 0;
}

void myWindow::changeObjectColor(float r, float g, float b)
{
    glm::vec3 diffuse_reflectivity = glm::vec3( r, g, b );

    GLuint location_diffuse_reflectivity = glGetUniformLocation( this->textureProgramHandle, "Kd"); 
    if( location_diffuse_reflectivity >= 0 ) 
    { 
        glUniform3fv( location_diffuse_reflectivity, 1, &diffuse_reflectivity[0]); 
    }
}

const int cantidadTramos = 16;
int cantVerticesCurva = 120;
int surfacePoints = 128;

GLfloat puntosControlSplineRecta[8][3] = {
	{0.0,0.0,0.0},
	{1.0,0.0,0.0},
	{2.0,0.0,0.0},
	{3.0,0.0,0.0},
	{4.0,0.0,0.0},
	{5.0,0.0,0.0},
	{6.0,0.0,0.0},
	{7.0,0.0,0.0}
};

GLfloat puntosControlSplineCurva[cantidadTramos+2][3] = {
	{0.0,0.0,0.0},
	{2.0,0.0,0.0},
	{4.0,0.0,0.0},
	{6.0,2.0,0.0},
	{6.0,4.0,0.0},
	{4.0,6.0,0.0},
	{2.0,6.0,0.0},
	{0.0,6.0,0.0},
	{-2.0,8.0,0.0},
	{-2.0,10.0,0.0},
	{0.0,12.0,0.0},
	{2.0,12.0,0.0},
	{4.0,12.0,0.0},
	{6.0,14.0,0.0},
	{6.0,16.0,0.0},
	{4.0,18.0,0.0},
	{2.0,18.0,0.0},
	{0.0,18.0,0.0}
};

GLfloat ctrlpoints[4][4][3] = {
 {{-1.5, 1.0, -1.5}, {-0.5, 1.0,-1.5 }, {0.5, 1.0, -1.5 }, {1.5, 1.0,-1.5}}, 
 {{-1.5, 1.0, -0.5}, {-0.5, 2.0,-0.5 }, {0.5, 2.0, -0.5 }, {1.5, 1.0,-0.5}}, 
 {{-1.5, 1.0,  0.5}, {-0.5, 2.0, 0.5 }, {0.5, 2.0,  0.5 }, {1.5, 1.0, 0.5}}, 
 {{-1.5, 1.0,  1.5}, {-0.5, 1.0, 1.5 }, {0.5, 1.0,  1.5 }, {1.5, 1.0, 1.5}}
};

float anguloEntreVectores2(Punto vec1, Punto vec2) {
	
	float norma1 = powf(vec1.x,2) + powf(vec1.y,2);
	norma1 = sqrt( norma1 );
	float norma2 = powf(vec2.x,2) + powf(vec2.y,2);
	norma2 = sqrt( norma2 );

	float prodNormas = norma1*norma2;

	float dotProduct = vec1.x*vec2.x + vec1.y*vec2.y;

	if( prodNormas == 0 ) return 0;

	float angulo = acos(dotProduct/prodNormas);

	return angulo;

}

float anguloEntreVectores(Punto vec1, Punto vec2) {
	
	if( vec1.x == 0 && vec1.y == 0 && vec1.z == 0 ) return 0;
	if( vec2.x == 0 && vec2.y == 0 && vec2.z == 0 ) return 0;

	Punto ejeX(1.0,0.0,0.0);

	float a1 = anguloEntreVectores2(vec1, ejeX);
	float a2 = anguloEntreVectores2(vec2, ejeX);

	return a1-a2;

}

int factorial(int n){
  return (n == 1 || n == 0) ? 1 : factorial(n - 1) * n;
}

float binomial_coefficient(int n, int i) {
  return (1.0f * factorial(n) / (factorial(i) * factorial(n-i)) );
}

float bernstein(int i, int n, float u) {
  return (binomial_coefficient(n-1, i) * powf(u, i) * powf(1-u, n-i-1) );
}

float baseSplineCuadratica(int i, float u) {

	// Normalizo el valor de u.
	while( u > 1.0f ) u -= 1.0f;

	// Resultado a devolver.
	float result = 0.0f;

	// 2 * B0(u)
	if( i == 0 ) result = (powf(u,2) - 2*u + 1);

	// 2 * B1(u)
	else if( i == 1 ) result = (-2*powf(u,2) + 2*u + 1);

	// 2 * B2(u)
	else if( i == 2 ) result = powf(u,2);

	// B(u)
	return result/2;
	
}

Punto splineCurve(float u, vector<Punto> puntosDeControl, unsigned tramo) {

	if( tramo > 9 ) {
		unsigned breakp = 0;
	}

	Punto res(0.0,0.0,0.0);

	for( unsigned i = 0 ; i < 3 ; i++ ) {
		res.x += puntosDeControl[i+tramo].x * baseSplineCuadratica(i,u);
		res.y += puntosDeControl[i+tramo].y * baseSplineCuadratica(i,u);
		res.z += puntosDeControl[i+tramo].z * baseSplineCuadratica(i,u);
	}

	return res;

}

Punto bezierSurface(float u, float v, int gradoU, int gradoV, vector<vector<Punto> > puntosDeControl){
	Punto resultado(0.0,0.0,0.0);
	for (int i=0; i<gradoU; i++){
		for(int j=0; j<gradoV; j++){
			resultado.x+=bernstein(j,gradoV,v)*bernstein(i,gradoU,u)*puntosDeControl[i][j].x;
			resultado.y+=bernstein(j,gradoV,v)*bernstein(i,gradoU,u)*puntosDeControl[i][j].y;
			resultado.z+=bernstein(j,gradoV,v)*bernstein(i,gradoU,u)*puntosDeControl[i][j].z;
		}
	}
	return resultado;

}

Punto bezierCurve(float u, int gradoU, vector<Punto> puntosDeControl){
	Punto resultado(0.0,0.0,0.0);
	for (int i=0; i<gradoU; i++){
		resultado.x+=bernstein(i,gradoU,u)*puntosDeControl[i].x;
		resultado.y+=bernstein(i,gradoU,u)*puntosDeControl[i].y;
		resultado.z+=bernstein(i,gradoU,u)*puntosDeControl[i].z;
	}
	return resultado;
}

void myWindow::createSurfaceOfRevolution(vector<Punto> controlPoints, string name){
	
	int grade = 4;

	float precision = 0.1;

	vector<glm::vec3> firstLine;
	vector<glm::vec3> secondLine;
	vector<glm::vec3> firstLineNormals;
	vector<glm::vec3> secondLineNormals;
	int line = 0;

	int nCurves = controlPoints.size()/grade;
	
	float angle = 15;

	for (int i = 0 ; i <= 360 ; i += angle ){
		
		for (int x = 0 ; x < nCurves ; x++){
			
			for (float j = 0 ; j < 1.0 + precision ; j += precision) {
				int init = x*grade;
				int end = (x+1)*grade;
				vector<Punto> tmpControlPoints;
				for (int pos = init ; pos < end ; pos++){
					Punto tmpPoint = controlPoints[pos];
					tmpControlPoints.push_back(tmpPoint );
				}
				Punto p = bezierCurve(j,grade,tmpControlPoints);
				// Variables para la aproximacion de normales
				Punto auxForward = bezierCurve(j + precision/10,grade,tmpControlPoints);
				Punto auxBackward = bezierCurve(j - precision/10,grade,tmpControlPoints);
				Punto dU = auxForward - auxBackward;
				glm::vec4 pV = glm::rotate(0.1f,glm::vec3(0,0,1))*glm::vec4(p.x,p.y,p.z,1.0);
				auxForward = Punto(pV.x,pV.y,pV.z);
				pV = glm::rotate(-0.1f,glm::vec3(0,0,1))*glm::vec4(p.x,p.y,p.z,1.0);
				auxBackward = Punto(pV.x,pV.y,pV.z);
				Punto dV = auxForward - auxBackward;

				//Calculamos la normal con el producto vectorial entre dU y dV
				glm::vec3 vec1 = glm::vec3(dV.x, dV.y, dV.z);
				glm::vec3 vec2 = glm::vec3(dU.x, dU.y, dU.z);
				glm::vec3 normal = glm::cross(vec1, vec2);

				normal = glm::normalize(normal);

				if (line == 0){
					firstLine.push_back(glm::vec3(p.x,p.y,p.z));
					firstLineNormals.push_back(normal);
				} else if (line == 1){
					secondLine.push_back(glm::vec3(p.x,p.y,p.z)); 
					secondLineNormals.push_back(normal);
				}
			}
		}

		glm::mat4 mat4 = glm::rotate(angle,glm::vec3(0,0,1));
		for (int in = 0 ; in < controlPoints.size() ; in++ ){
			glm::vec4 vec4 = glm::vec4(controlPoints[in].x,controlPoints[in].y,controlPoints[in].z,1.0);
			vec4 = mat4*vec4;
			controlPoints[in] = Punto(vec4.x ,vec4.y, vec4.z);
		}

		line++;
		if (line == 2){
			glm::vec3 top;
			for (int cont = 0; cont < firstLine.size() ; cont++){
				sor_vertex_buffer[name].push_back(firstLine[cont]);
				sor_normal_buffer[name].push_back(firstLineNormals[cont]);
				sor_vertex_buffer[name].push_back(secondLine[cont]);
				sor_normal_buffer[name].push_back(secondLineNormals[cont]);

				firstLine[cont] = secondLine[cont];
				firstLineNormals[cont] = secondLineNormals[cont];
					
				
			}
			line = 1;
			secondLine.clear();
			secondLineNormals.clear();
		}
	}
	
}

void myWindow::renderSurfaceOfRevolution(glm::mat4 modelMatrix, string name){
	
	// Normal Matrix
    glm::mat3 normal_matrix = inverse ( transpose (glm::mat3 ( modelMatrix ) ) );
        
    // Bind Normal MAtrix
    GLuint location_normal_matrix = glGetUniformLocation( this->textureProgramHandle, "NormalMatrix"); 
    if( location_normal_matrix >= 0 ) 
    { 
        glUniformMatrix3fv( location_normal_matrix, 1, GL_FALSE, &normal_matrix[0][0]); 
    }

	 // Bind Model Matrix
    GLuint location_model_matrix = glGetUniformLocation( this->textureProgramHandle, "ModelMatrix"); 
    if( location_model_matrix >= 0 ) 
    { 
        glUniformMatrix4fv( location_model_matrix, 1, GL_FALSE, &modelMatrix[0][0]); 
    }
	
	 // Bind Normal MAtrix
    location_normal_matrix = glGetUniformLocation( this->textureNONSHADOWProgramHandle, "NormalMatrix"); 
    if( location_normal_matrix >= 0 ) 
    { 
        glUniformMatrix3fv( location_normal_matrix, 1, GL_FALSE, &normal_matrix[0][0]); 
    }

	 // Bind Model Matrix
    location_model_matrix = glGetUniformLocation( this->textureNONSHADOWProgramHandle, "ModelMatrix"); 
    if( location_model_matrix >= 0 ) 
    { 
        glUniformMatrix4fv( location_model_matrix, 1, GL_FALSE, &modelMatrix[0][0]); 
    }
	
	 // Bind Normal MAtrix
	location_normal_matrix = glGetUniformLocation( this->specularProgramHandle, "NormalMatrix"); 
    if( location_normal_matrix >= 0 ) 
    { 
        glUniformMatrix3fv( location_normal_matrix, 1, GL_FALSE, &normal_matrix[0][0]); 
    }

	 // Bind Model Matrix
    location_model_matrix = glGetUniformLocation( this->specularProgramHandle, "ModelMatrix"); 
    if( location_model_matrix >= 0 ) 
    { 
        glUniformMatrix4fv( location_model_matrix, 1, GL_FALSE, &modelMatrix[0][0]); 
    }

	// Bind Model Matrix to shadow program
	GLuint shadow_model_matrix = glGetUniformLocation( this->shadowProgramHandle, "ModelMatrix"); 
	if( location_model_matrix >= 0 ) 
	{ 
		glUniformMatrix4fv( shadow_model_matrix, 1, GL_FALSE, &modelMatrix[0][0]); 
	}

	if (sor_normal_buffer.count(name) == 0) return;

	initTexture("textures/leaf.png");

	glBegin(GL_TRIANGLE_STRIP);
	for (int i = 0 ; i < sor_vertex_buffer[name].size() ; i++) {

		if (sor_normal_buffer[name].size() <= i) continue;
		glm::vec3 n = sor_normal_buffer[name][i];
		glNormal3f(n.x,n.y,n.z);

		glm::vec3 p = sor_vertex_buffer[name][i];
		glm::vec4 v = glm::vec4(p.x,p.y,p.z,1.0);
		glTexCoord2f(v.x,v.y);
		glVertex3d(v.x,v.y,v.z);	

	}
	glEnd();
}

void myWindow::createTreeCup(){

	vector<Punto> controlPoints;
	controlPoints.push_back(Punto(0.15,0,0.0));
	controlPoints.push_back(Punto(0.6,0,0.3));
	controlPoints.push_back(Punto(0.8,0,0.5));
	controlPoints.push_back(Punto(0.9,0,0.8));
	controlPoints.push_back(Punto(0.85,0,1.0));
	controlPoints.push_back(Punto(0.6,0,1.3));
	controlPoints.push_back(Punto(0.2,0,2.0));
	controlPoints.push_back(Punto(0,0,2.01));

	stringstream ss;
	ss << nTrees;
	string name = "Tree " + ss.str();
	createSurfaceOfRevolution(controlPoints, name );

	nTrees++;
}

void myWindow::renderTree(glm::mat4 modelMatrix, string name){
	
	glm::mat4 m1 = glm::translate(modelMatrix,glm::vec3(0.0f,0.0f,0.8f));
	renderSurfaceOfRevolution(m1,name);

	glm::mat4 m2 = glm::translate(modelMatrix,glm::vec3(0.0f,0.0f,0.5f));
	m2 = glm::scale(m2,glm::vec3(0.6f,0.6f,1));
	renderAltCylinder(m2,"textures/trunk.png");
	
}

void myWindow::renderPipe(glm::mat4 model_matrix) {

	glm::mat4 m = glm::mat4(model_matrix);

	for( unsigned i = 0 ; i < 1 ; i++ ) {

		this->renderSweepSurface(m);
		
	}
}

void myWindow::setUpCamera(){

	// View (camera) Matrix
	cameraTheeta+=cameraTheetaSpeed;
	cameraPhi+=cameraPhiSpeed;
	if (cameraPhi>=90) cameraPhi = 90;
	else if (cameraPhi<=-90) cameraPhi = -90;

	if (cameraTheeta>=180) cameraTheeta = -180;
	else if (cameraTheeta<=-180) cameraTheeta = 180;

	if ( cameraPerspectiveType == CAMERA_WASD ) {
		if (flag){     
			cameraEyeY+=cameraEyeYSpeed*sin(degreesToRadians(cameraTheeta));
			cameraEyeX+=cameraEyeXSpeed*cos(degreesToRadians(cameraTheeta));
			mirrorOffsetH+=cameraEyeYSpeed/5*sin(degreesToRadians(cameraTheeta));
			mirrorOffsetH-=cameraEyeXSpeed/5*cos(degreesToRadians(cameraTheeta));
			if (mirrorOffsetH<=0.0) mirrorOffsetH=0.0;
		}
		else{
			cameraEyeX+=cameraEyeXSpeed*sin(degreesToRadians(cameraTheeta)); 
			cameraEyeY+=cameraEyeYSpeed*cos(degreesToRadians(cameraTheeta));        
		}

		cameraEyeZ+=cameraEyeZSpeed;
		lookAtY=cameraEyeY+cos(degreesToRadians(cameraTheeta));
		lookAtX=cameraEyeX+sin(degreesToRadians(cameraTheeta))*cos(degreesToRadians(cameraPhi));
		lookAtZ=cameraEyeZ+sin(degreesToRadians(cameraPhi));
	}

	if ( cameraPerspectiveType == CAMERA_ORBIT ) {

		lookAtY=orbitCenterY;
		lookAtX=orbitCenterX;
		lookAtZ=orbitCenterZ;

		cameraEyeY=orbitRadius*sin(degreesToRadians(cameraTheeta)) + lookAtY;
		cameraEyeX=orbitRadius*cos(degreesToRadians(cameraTheeta)) + lookAtX;     
		cameraEyeZ+=cameraEyeZSpeed;
	}

	if ( cameraPerspectiveType == CAMERA_CRANE ) {

		cameraEyeX = 100.0f + 1.0f * cos(degreesToRadians(90-craneAngle-craneAngleSpeed));
		cameraEyeY = 102.50f - 1.0f * sin(degreesToRadians(90-craneAngle-craneAngleSpeed));     
		cameraEyeZ = 110.7f;

		lookAtX = cameraEyeX + 60.0f * cos(degreesToRadians(craneAngle+craneAngleSpeed));
		lookAtY = cameraEyeY + 60.0f * sin(degreesToRadians(craneAngle+craneAngleSpeed));
		lookAtZ = cameraEyeZ;

	}

	this->view_matrix = glm::lookAt ( glm::vec3 ( cameraEyeX, cameraEyeY, cameraEyeZ ),
		glm::vec3 ( lookAtX, lookAtY, lookAtZ),
		glm::vec3 ( 0.0, 0.0, 1.0 ) );

	vec3 eyeVector = vec3(lookAtX - cameraEyeX, lookAtY - cameraEyeY, -lookAtZ + cameraEyeZ);
	eyeVector = normalize(eyeVector);

	GLuint location_eye_vector = glGetUniformLocation( this->textureProgramHandle, "EyeVector"); 
	if( location_eye_vector >= 0 )
		glUniform3fv( location_eye_vector, 1, &eyeVector[0]);
}

vec3 crossProd(vec3 v1, vec3 v2){
	vec3 result = vec3(0.0,0.0,0.0);
	result.x = v1.x*v2.y-v1.y*v2.x;
	result.y = v1.z*v2.x-v1.x*v2.z;
	result.z = v1.y*v2.z-v1.z*v2.y;
	return result;
}

glm::vec3 calcularNormal(float u,float v,int grU,int grV,vector<vector<Punto> > vect,Punto punto, float precision){
	//Calculamos el vector tangente en V
	int offV;
	offV = v+precision/4;
	Punto aux = bezierSurface(u,offV,grU,grV,vect);
	Punto derivV; 
	derivV= aux-punto;

	//Calculamos el vector tangente en U
	int offU;
	offU = u+precision/4;
	aux = bezierSurface(offU,v,grU,grV,vect);
	Punto derivU; 
	derivU= aux-punto;

	//Calculamos la normal con el producto vectorial entre dU y dV
	glm::vec3 vec1 = glm::vec3(derivV.x, derivV.y, derivV.z);
	glm::vec3 vec2 = glm::vec3(derivU.x, derivU.y, derivU.z);
	glm::vec3 normal = crossProd(vec2, vec1);
	
	//Normalizamos
	normal = glm::normalize(normal);

	return normal;
}

float cantVerticesSup = 10;

void myWindow::createSurfaces(){

	int gradoU=4;
	int gradoV=4;

	vector <vector<Punto> > vect(gradoU,gradoV);
	vect[0][0]= Punto(0.0,0.0,0.0);
	vect[0][1]= Punto(3.0,3.0,0.0);
	vect[0][2]= Punto(6.0,3.0,0.0);
	vect[0][3]= Punto(9.0,0.0,0.0);

	vect[1][0]= Punto(-3.0,-3.0,0.0);
	vect[1][1]= Punto(3.0,-3.0,9.0);
	vect[1][2]= Punto(6.0,-3.0,9.0);
	vect[1][3]= Punto(12.0,-3.0,0.0);
	
	vect[2][0]= Punto(-3.0,-6.0,0.0);
	vect[2][1]= Punto(13.0,-6.0,9.0);
	vect[2][2]= Punto(6.0,-6.0,9.0);
	vect[2][3]= Punto(12.0,-6.0,0.0);

	vect[3][0]= Punto(0.0,-9.0,0.0);
	vect[3][1]= Punto(3.0,-12.0,0.0);
	vect[3][2]= Punto(6.0,-12.0,0.0);
	vect[3][3]= Punto(9.0,-9.0,0.0);

	float precision = (float)1/cantVerticesSup;
	
	float u = 0.0;
	vector <vector <Punto> > resultado;  
	
	//Sumamos precision para evitar errores de comparacion de floats
	while (u<1.0+precision/2){
		if (u>=1.0)
			u=1.0;
		float v = 0.0;
		vector <Punto> temp;
		Punto punto;
		while (v<1.0+precision/2){
			if (v>=1.0) v =1.0;
			punto = bezierSurface(u,v,gradoU,gradoV,vect);
			glm::vec3 normal = calcularNormal(u,v,gradoU,gradoV,vect,punto,precision);
			punto.setNormal(normal);
			punto.setUV(u,v);
			temp.push_back(punto);
			v+=precision;
		}
		resultado.push_back(temp);
		u+=precision;
	}

	superficies["monticulo"] = resultado;
}

void myWindow::renderMonticulo(mat4 model_matrix, char* textura){
	changeObjectColor(1.0, 1.0, 1.0);
	vector<vector <Punto> > aEscribir = superficies["monticulo"];
	model_matrix = scale(model_matrix, glm::vec3(0.5f,0.5f,0.5f));

	// Normal Matrix
    glm::mat3 normal_matrix = inverse ( transpose (glm::mat3 ( model_matrix ) ) );
        
    // Bind Normal Matrix
    GLuint location_normal_matrix = glGetUniformLocation( this->textureProgramHandle, "NormalMatrix"); 
    if( location_normal_matrix >= 0 ) 
    { 
        glUniformMatrix3fv( location_normal_matrix, 1, GL_FALSE, &normal_matrix[0][0]); 
    }

	// Bind Model Matrix
    GLuint location_model_matrix = glGetUniformLocation( this->textureProgramHandle, "ModelMatrix"); 
    if( location_model_matrix >= 0 ) 
    { 
        glUniformMatrix4fv( location_model_matrix, 1, GL_FALSE, &model_matrix[0][0]); 
    }

	// Bind Normal MAtrix
    location_normal_matrix = glGetUniformLocation( this->textureNONSHADOWProgramHandle, "NormalMatrix"); 
    if( location_normal_matrix >= 0 ) 
    { 
        glUniformMatrix3fv( location_normal_matrix, 1, GL_FALSE, &normal_matrix[0][0]); 
    }

	// Bind Model Matrix
    location_model_matrix = glGetUniformLocation( this->textureNONSHADOWProgramHandle, "ModelMatrix"); 
    if( location_model_matrix >= 0 ) 
    { 
        glUniformMatrix4fv( location_model_matrix, 1, GL_FALSE, &model_matrix[0][0]); 
    }

	// Bind Model Matrix to shadow program
	GLuint shadow_model_matrix = glGetUniformLocation( this->shadowProgramHandle, "ModelMatrix"); 
	if( location_model_matrix >= 0 ) 
	{ 
		glUniformMatrix4fv( shadow_model_matrix, 1, GL_FALSE, &model_matrix[0][0]); 
	}

	initTexture(textura);
	for (int i=0;i<cantVerticesSup;i++){
		glBegin(GL_TRIANGLE_STRIP);
		
		for (int j=0;j<=cantVerticesSup;j++){
			
			Punto punto = aEscribir[i][j];
			glNormal3f (punto.getNormal().x,punto.getNormal().y,punto.getNormal().z);
			glm::vec4 vec4 = glm::vec4(punto.x,punto.y,punto.z,1.0);
			glTexCoord2f (punto.u,punto.v);
		
			glVertex3d(vec4.x,vec4.y,vec4.z);

			Punto punto2 = aEscribir[i+1][j];
			glNormal3f (punto2.getNormal().x,punto2.getNormal().y,punto2.getNormal().z);
			glm::vec4 vecAux = glm::vec4(punto2.x,punto2.y,punto2.z,1.0);
			
			glTexCoord2f (punto2.u,punto2.v);
	
			glVertex3d(vecAux.x,vecAux.y,vecAux.z);

	
		}
		glEnd();
	}



}

void myWindow::renderPilaDeArena(mat4 model_matrix, char* texture){
	//Ojimetro mode ON
	//model_matrix = translate(model_matrix,vec3(0.0,0.0,-0.5));
	mat4 m = scale(model_matrix, vec3(0.7,0.5,0.7));
	this->renderMonticulo(m, texture);

	mat4 m2 = scale(model_matrix, vec3(-0.5,0.7,0.7));
	m2 = rotate(m2, 90.0f, glm::vec3(0.0,0.0,1.0));
	m2 = translate(m2,vec3(-3.0,2.0,0.0));
	this->renderMonticulo(m2, texture);

	mat4 m3 = scale(model_matrix, vec3(0.6,0.7,0.7));
	m3 = rotate(m3, 45.0f, glm::vec3(0.0,0.0,1.0));
	m3 = translate(m3,vec3(-2.0,2.0,0.0));
	this->renderMonticulo(m3, texture);
}

void myWindow::renderSurfaces(glm::mat4 model_matrix){
	
	changeObjectColor(1.0, 0.5, 1.0);
	vector<vector <Punto> > aEscribir = superficies["monticulo"];

	// Normal Matrix
    glm::mat3 normal_matrix = inverse ( transpose (glm::mat3 ( model_matrix ) ) );
        
    // Bind Normal MAtrix
    GLuint location_normal_matrix = glGetUniformLocation( this->textureProgramHandle, "NormalMatrix"); 
    if( location_normal_matrix >= 0 ) 
    { 
        glUniformMatrix3fv( location_normal_matrix, 1, GL_FALSE, &normal_matrix[0][0]); 
    }

	 // Bind Model Matrix
    GLuint location_model_matrix = glGetUniformLocation( this->textureProgramHandle, "ModelMatrix"); 
    if( location_model_matrix >= 0 ) 
    { 
        glUniformMatrix4fv( location_model_matrix, 1, GL_FALSE, &model_matrix[0][0]); 
    }
	 // Bind Normal MAtrix
    location_normal_matrix = glGetUniformLocation( this->textureNONSHADOWProgramHandle, "NormalMatrix"); 
    if( location_normal_matrix >= 0 ) 
    { 
        glUniformMatrix3fv( location_normal_matrix, 1, GL_FALSE, &normal_matrix[0][0]); 
    }

	 // Bind Model Matrix
    location_model_matrix = glGetUniformLocation( this->textureNONSHADOWProgramHandle, "ModelMatrix"); 
    if( location_model_matrix >= 0 ) 
    { 
        glUniformMatrix4fv( location_model_matrix, 1, GL_FALSE, &model_matrix[0][0]); 
    }

	// Bind Model Matrix to shadow program
	GLuint shadow_model_matrix = glGetUniformLocation( this->shadowProgramHandle, "ModelMatrix"); 
	if( location_model_matrix >= 0 ) 
	{ 
		glUniformMatrix4fv( shadow_model_matrix, 1, GL_FALSE, &model_matrix[0][0]); 
	}

	
	int indic = 0;
	for (int i=0;i<cantVerticesSup;i++){
		glBegin(GL_TRIANGLE_STRIP);

		for (int j=0;j<=cantVerticesSup;j++){
			

			Punto punto = aEscribir[i][j];
			
			glNormal3f (punto.getNormal().x,punto.getNormal().y,punto.getNormal().z);
			glm::vec4 vec4 = glm::vec4(punto.x,punto.y,punto.z,1.0);
		
			glVertex3d(vec4.x,vec4.y,vec4.z);
			
			Punto punto2 = aEscribir[i+1][j];
			glNormal3f (punto2.getNormal().x,punto2.getNormal().y,punto2.getNormal().z);
			glm::vec4 vecAux = glm::vec4(punto2.x,punto2.y,punto2.z,1.0);
			glTexCoord2f(punto2.u,punto2.v);
			glVertex3d(vecAux.x,vecAux.y,vecAux.z);

	
		}
		glEnd();
	}

}

void myWindow::createCurves(){
	vector<Punto> vect(3);
	vect[0] = Punto(0.0,0.0,0.0);
	vect[1] = Punto(10.0,0.0,0.0);
	vect[2] = Punto(20.0,10.0,0.0);

	float precision = (float)1/cantVerticesSup;
	
	float u = 0.0;
	vector <Punto> resultado;  

	//Sumamos precision para evitar errores de comparacion de floats
	while (u<=1.0+precision/2){
		if (u>=1.0) u = 1.0;
		Punto punto = bezierCurve(u,3,vect);
		resultado.push_back(punto);
		u+=precision;
	}
	
	curvas["Test"] = resultado;
}

void myWindow::createSplines() {

	float precision = (float)cantidadTramos/cantVerticesCurva;

	// Tramo curvo de superficie de barrido:
	vector<Punto> vect(2+cantidadTramos);

	// Genero vector de puntos de control
	for( unsigned i = 0 ; i < cantidadTramos+2 ; i++ ) {
	
		vect[i] = Punto(puntosControlSplineCurva[i][0],puntosControlSplineCurva[i][1],puntosControlSplineCurva[i][2]);

	}

	vector <Punto> resultado;
	for( unsigned tramo = 0 ; tramo < cantidadTramos ; tramo++ ) {
		float u = 0.0;
		//Sumamos precision para evitar errores de comparacion de floats
		while (u<=1.0+precision/2){
			if (u>=1.0) u = 1.0;
			Punto punto = splineCurve(u,vect,tramo);
			resultado.push_back(punto);
			u+=precision;
		}
	}
	
	curvas["SplineCurva"] = resultado;

}

void myWindow::renderCurves(glm::mat4 model_matrix){
	
    changeObjectColor(0.0f, 0.5f, 0.5f);
	vector <Punto> aEscribir = curvas["SplineCurva"];
	
	for (int i=0;i<cantVerticesCurva+cantidadTramos;i++){
		glBegin(GL_LINE_STRIP);
		Punto punto = aEscribir[i];
		glm::vec4 vec4 = glm::vec4(punto.x,punto.y,punto.z,1.0);
		//Aca aplicamos transformacion al punto.
		vec4 = model_matrix*vec4;
		glVertex3d(vec4.x,vec4.y,vec4.z);

		Punto punto2 = aEscribir[i+1];
		glm::vec4 vec = glm::vec4(punto2.x,punto2.y,punto2.z,1.0);
		//Aca aplicamos transformacion al punto.
		vec = model_matrix*vec;
		glVertex3d(vec.x,vec.y,vec.z);
		glEnd();

	}
	

}

void myWindow::createSweepSurface() {

        float PI                = 3.14159;
        float altoPipe  = 1.0f;
        float anchoPipe = 3.0f;

        vector< vector<Punto> > superficie;
        Punto auxPoint;
        
        vector<Punto> aEscribir = curvas["SplineCurva"];
        
        glm::vec4 vec4;
        glm::mat4 rotoTranslate;
        float anguloEntreTangentes;
        Punto tangenteAnterior(1.0,0.0,0.0);
        Punto punto1 = aEscribir[0];
        Punto punto2;

        // Marco Base
        glm::vec4 vecCubo0(punto1.x, punto1.y + anchoPipe/2, punto1.z + altoPipe/2,1.0);
        glm::vec4 vecCubo1(punto1.x, punto1.y + anchoPipe/2, punto1.z - altoPipe/2,1.0);
        glm::vec4 vecCubo2(punto1.x, punto1.y - anchoPipe/2, punto1.z + altoPipe/2,1.0);
        glm::vec4 vecCubo3(punto1.x, punto1.y - anchoPipe/2, punto1.z - altoPipe/2,1.0);

        for ( int i = 1 ; i < surfacePoints ; i++) {
                vector<Punto> temporal;

                punto2 = aEscribir[i];

                // Tangente actual aproximada.
                Punto tangente(punto2.x-punto1.x, punto2.y-punto1.y, punto2.z-punto1.z);

                // Angulo entre la tangente anterior y la actual.
                anguloEntreTangentes = anguloEntreVectores(tangente, tangenteAnterior)*180/PI;
                
                // Matriz de rototraslacion del marco.
                rotoTranslate = glm::translate(glm::mat4(1.0), glm::vec3(tangente.x, tangente.y, tangente.z));
                rotoTranslate = glm::translate(rotoTranslate, glm::vec3(punto1.x, punto1.y, 0.0));
                rotoTranslate = glm::rotate(rotoTranslate, anguloEntreTangentes, glm::vec3(0.0,0.0,1.0));
                rotoTranslate = glm::translate(rotoTranslate, glm::vec3(-punto1.x, -punto1.y, 0.0));

                // Nuevo marco.
                glm::vec4 vecCubo4 = rotoTranslate * vecCubo0;
                glm::vec4 vecCubo5 = rotoTranslate * vecCubo1;
                glm::vec4 vecCubo6 = rotoTranslate * vecCubo2;
                glm::vec4 vecCubo7 = rotoTranslate * vecCubo3;
                
                // Normal cara izquierda.
                glm::vec4 normal1 = glm::vec4(vecCubo0.x-vecCubo2.x, vecCubo0.y-vecCubo2.y, 0.0, 1.0);
                normal1 = glm::normalize(normal1);
                // Normal cara derecha.
                glm::vec4 normal2 = glm::vec4(vecCubo2.x-vecCubo0.x, vecCubo2.y-vecCubo0.y, 0.0, 1.0);
                normal2 = glm::normalize(normal2);

                // Cara izquierda (0-4-1  4-1-5)
                vec4 = vecCubo0;
                auxPoint = Punto(vec4.x,vec4.y,vec4.z);
                auxPoint.setNormal(glm::vec3(normal1.x, normal1.y, 0.0f));
                temporal.push_back(auxPoint);
                vec4 = vecCubo4;
                auxPoint = Punto(vec4.x,vec4.y,vec4.z);
                auxPoint.setNormal(glm::vec3(normal1.x, normal1.y, 0.0f));
                temporal.push_back(auxPoint);
                vec4 = vecCubo1;
                auxPoint = Punto(vec4.x,vec4.y,vec4.z);
                auxPoint.setNormal(glm::vec3(normal1.x, normal1.y, 0.0f));
                temporal.push_back(auxPoint);
                vec4 = vecCubo5;
                auxPoint = Punto(vec4.x,vec4.y,vec4.z);
                auxPoint.setNormal(glm::vec3(normal1.x, normal1.y, 0.0f));
                temporal.push_back(auxPoint);

                // Cara inferior (1-5-3  5-3-7)
                vec4 = vecCubo3;
                auxPoint = Punto(vec4.x,vec4.y,vec4.z);
                auxPoint.setNormal(glm::vec3(0.0f, 0.0f, -1.0f));
                temporal.push_back(auxPoint);
                vec4 = vecCubo7;
                auxPoint = Punto(vec4.x,vec4.y,vec4.z);
                auxPoint.setNormal(glm::vec3(0.0f, 0.0f, -1.0f));
                temporal.push_back(auxPoint);
                
                // Cara derecha (3-7-2  7-2-6)
                vec4 = vecCubo2;
                auxPoint = Punto(vec4.x,vec4.y,vec4.z);
                auxPoint.setNormal(glm::vec3(normal2.x, normal2.y, 0.0f));
                temporal.push_back(auxPoint);
                vec4 = vecCubo6;
                auxPoint = Punto(vec4.x,vec4.y,vec4.z);
                auxPoint.setNormal(glm::vec3(normal2.x, normal2.y, 0.0f));
                temporal.push_back(auxPoint);
                
                // Cara superior (2-6-0  6-0-4)
                vec4 = vecCubo0;
                auxPoint = Punto(vec4.x,vec4.y,vec4.z);
                auxPoint.setNormal(glm::vec3(0.0f, 0.0f, 1.0f));
                temporal.push_back(auxPoint);
                vec4 = vecCubo4;
                auxPoint = Punto(vec4.x,vec4.y,vec4.z);
                auxPoint.setNormal(glm::vec3(0.0f, 0.0f, 1.0f));
                temporal.push_back(auxPoint);

                // Reasignacion de puntos y tangentes.
                tangenteAnterior = tangente;
                punto1 = punto2;
                vecCubo0 = vecCubo4;
                vecCubo1 = vecCubo5;
                vecCubo2 = vecCubo6;
                vecCubo3 = vecCubo7;

                superficie.push_back(temporal);

        }

        superficies["SweepCurva"] = superficie;

}

void myWindow::renderSweepSurface(glm::mat4 model_matrix) {

	vector< vector<Punto> > aEscribir;

	// Normal Matrix
	glm::mat3 normal_matrix = inverse ( transpose (glm::mat3 ( model_matrix ) ) );

	// Bind Normal MAtrix
	GLuint location_normal_matrix = glGetUniformLocation( this->textureProgramHandle, "NormalMatrix"); 
	if( location_normal_matrix >= 0 ) 
	{ 
		glUniformMatrix3fv( location_normal_matrix, 1, GL_FALSE, &normal_matrix[0][0]); 
	}

	// Bind Model Matrix
	GLuint location_model_matrix = glGetUniformLocation( this->textureProgramHandle, "ModelMatrix"); 
	if( location_model_matrix >= 0 ) 
	{ 
		glUniformMatrix4fv( location_model_matrix, 1, GL_FALSE, &model_matrix[0][0]); 
	}

	// Bind Normal MAtrix
	location_normal_matrix = glGetUniformLocation( this->textureNONSHADOWProgramHandle, "NormalMatrix"); 
	if( location_normal_matrix >= 0 ) 
	{ 
		glUniformMatrix3fv( location_normal_matrix, 1, GL_FALSE, &normal_matrix[0][0]); 
	}

	// Bind Model Matrix
	location_model_matrix = glGetUniformLocation( this->textureNONSHADOWProgramHandle, "ModelMatrix"); 
	if( location_model_matrix >= 0 ) 
	{ 
		glUniformMatrix4fv( location_model_matrix, 1, GL_FALSE, &model_matrix[0][0]); 
	}
	// Bind Model Matrix to shadow program
	GLuint shadow_model_matrix = glGetUniformLocation( this->shadowProgramHandle, "ModelMatrix"); 
	if( location_model_matrix >= 0 ) 
	{ 
		glUniformMatrix4fv( shadow_model_matrix, 1, GL_FALSE, &model_matrix[0][0]); 
	}

	initTexture("textures/metal.png");

	aEscribir = superficies["SweepCurva"];

	unsigned u = 0;

	for (int i=0;i<surfacePoints-1;i++){

		glBegin(GL_TRIANGLE_STRIP);
		for(int j = 0 ; j < 10 ; j++) {

			Punto puntoActual = aEscribir[i][j];
			glm::vec4 verticeActual = glm::vec4(puntoActual.x,puntoActual.y,puntoActual.z,1.0);
			glm::vec4 modelVertex = verticeActual;
			glNormal3f (puntoActual.normal.x, puntoActual.normal.y, puntoActual.normal.z);
			glTexCoord2f(modelVertex.x + modelVertex.z,modelVertex.y + modelVertex.z);
			glVertex3d(modelVertex.x,modelVertex.y,modelVertex.z);

		}
		glEnd();

	}

	unsigned w = 0;

}

void myWindow::initTextureShaderParams(vec3 lightPos, mat4 projection_matrix, mat4 model_matrix){
	// Bind View Matrix
	GLuint location_view_matrix_texture = glGetUniformLocation( this->textureProgramHandle, "ViewMatrix"); 
	if( location_view_matrix_texture >= 0 )
		glUniformMatrix4fv( location_view_matrix_texture, 1, GL_FALSE, &view_matrix[0][0]);

	// Bind View MAtrix
	GLuint location_projection_matrix_texture = glGetUniformLocation( this->textureProgramHandle, "ProjectionMatrix"); 
	if( location_projection_matrix_texture >= 0 )
		glUniformMatrix4fv( location_projection_matrix_texture, 1, GL_FALSE, &projection_matrix[0][0]);

	// Bind Light Settings
	glm::vec4 light_position_texture = glm::vec4( lightPos, 1.0f );
	float uniformLight = 1.7f;
	glm::vec3 light_intensity_texture = glm::vec3( uniformLight,uniformLight,uniformLight );
	glm::vec3 diffuse_reflectivity_texture = glm::vec3( 1.0f, 1.0f, 1.0f );

	GLuint location_light_position_texture = glGetUniformLocation( this->textureProgramHandle, "LightPosition"); 
	if( location_light_position_texture >= 0 )
		glUniform4fv( location_light_position_texture, 1, &light_position_texture[0]);

	GLuint location_light_intensity_texture = glGetUniformLocation( this->textureProgramHandle, "Ld"); 
	if( location_light_intensity_texture >= 0 )
		glUniform3fv( location_light_intensity_texture, 1, &light_intensity_texture[0]);

	GLuint diffuse_reflectivity_location_texture = glGetUniformLocation( this->textureProgramHandle, "Kd"); 
	if( diffuse_reflectivity_location_texture >= 0 )
		glUniform3fv( diffuse_reflectivity_location_texture, 1, &diffuse_reflectivity_texture[0]);
	
}

void myWindow::initTextureNONSHADOWShaderParams(vec3 lightPos, mat4 projection_matrix, mat4 model_matrix){
	// Bind View Matrix
	GLuint location_view_matrix_texture = glGetUniformLocation( this->textureNONSHADOWProgramHandle, "ViewMatrix"); 
	if( location_view_matrix_texture >= 0 )
		glUniformMatrix4fv( location_view_matrix_texture, 1, GL_FALSE, &view_matrix[0][0]);

	// Bind View MAtrix
	GLuint location_projection_matrix_texture = glGetUniformLocation( this->textureNONSHADOWProgramHandle, "ProjectionMatrix"); 
	if( location_projection_matrix_texture >= 0 )
		glUniformMatrix4fv( location_projection_matrix_texture, 1, GL_FALSE, &projection_matrix[0][0]);

	// Bind Light Settings
	glm::vec4 light_position_texture = glm::vec4( lightPos, 1.0f );
	float uniformLight = 1.7f;
	glm::vec3 light_intensity_texture = glm::vec3( uniformLight,uniformLight,uniformLight );
	glm::vec3 diffuse_reflectivity_texture = glm::vec3( 1.0f, 1.0f, 1.0f );

	GLuint location_light_position_texture = glGetUniformLocation( this->textureNONSHADOWProgramHandle, "LightPosition"); 
	if( location_light_position_texture >= 0 )
		glUniform4fv( location_light_position_texture, 1, &light_position_texture[0]);

	GLuint location_light_intensity_texture = glGetUniformLocation( this->textureNONSHADOWProgramHandle, "Ld"); 
	if( location_light_intensity_texture >= 0 )
		glUniform3fv( location_light_intensity_texture, 1, &light_intensity_texture[0]);

	GLuint diffuse_reflectivity_location_texture = glGetUniformLocation( this->textureNONSHADOWProgramHandle, "Kd"); 
	if( diffuse_reflectivity_location_texture >= 0 )
		glUniform3fv( diffuse_reflectivity_location_texture, 1, &diffuse_reflectivity_texture[0]);

	vec3 specularIntensity = vec3(1.3,1.3,1.3);
	GLuint specular_intensity_location = glGetUniformLocation( this->textureNONSHADOWProgramHandle, "SpecularIntensity"); 
	if( specular_intensity_location >= 0 )
		glUniform3fv( specular_intensity_location, 1, &specularIntensity[0]);
	
}

void myWindow::initSpecularNONSHADOWShaderParams(vec3 lightPos, mat4 projection_matrix, mat4 model_matrix){
	// Bind View Matrix
	GLuint location_view_matrix_texture = glGetUniformLocation( this->specularNONSHADOWProgramHandle, "ViewMatrix"); 
	if( location_view_matrix_texture >= 0 )
		glUniformMatrix4fv( location_view_matrix_texture, 1, GL_FALSE, &view_matrix[0][0]);

	// Bind View MAtrix
	GLuint location_projection_matrix_texture = glGetUniformLocation( this->specularNONSHADOWProgramHandle, "ProjectionMatrix"); 
	if( location_projection_matrix_texture >= 0 )
		glUniformMatrix4fv( location_projection_matrix_texture, 1, GL_FALSE, &projection_matrix[0][0]);

	// Bind Light Settings
	glm::vec4 light_position_texture = glm::vec4( lightPos, 1.0f );
	float uniformLight = 1.7f;
	glm::vec3 light_intensity_texture = glm::vec3( uniformLight,uniformLight,uniformLight );
	glm::vec3 diffuse_reflectivity_texture = glm::vec3( 1.0f, 1.0f, 1.0f );

	GLuint location_light_position_texture = glGetUniformLocation( this->specularNONSHADOWProgramHandle, "LightPosition"); 
	if( location_light_position_texture >= 0 )
		glUniform4fv( location_light_position_texture, 1, &light_position_texture[0]);

	GLuint location_light_intensity_texture = glGetUniformLocation( this->specularNONSHADOWProgramHandle, "Ld"); 
	if( location_light_intensity_texture >= 0 )
		glUniform3fv( location_light_intensity_texture, 1, &light_intensity_texture[0]);

	GLuint diffuse_reflectivity_location_texture = glGetUniformLocation( this->specularNONSHADOWProgramHandle, "Kd"); 
	if( diffuse_reflectivity_location_texture >= 0 )
		glUniform3fv( diffuse_reflectivity_location_texture, 1, &diffuse_reflectivity_texture[0]);

	vec3 specularIntensity = vec3(1.3,1.3,1.3);
	GLuint specular_intensity_location = glGetUniformLocation( this->specularNONSHADOWProgramHandle, "SpecularIntensity"); 
	if( specular_intensity_location >= 0 )
		glUniform3fv( specular_intensity_location, 1, &specularIntensity[0]);
}

void myWindow::initNormalMapNONSHADOWShaderParams(vec3 lightPos, mat4 projection_matrix, mat4 model_matrix){
	// Bind View Matrix
	GLuint location_view_matrix_texture = glGetUniformLocation( this->normalMappingNONSHADOWProgramHandle, "ViewMatrix"); 
	if( location_view_matrix_texture >= 0 ){
		glUniformMatrix4fv( location_view_matrix_texture, 1, GL_FALSE, &view_matrix[0][0]);
	} else {
		cerr << "Error al bindear ViewMatrix" << endl;
	}

	// Bind View MAtrix
	GLuint location_projection_matrix_texture = glGetUniformLocation( this->normalMappingNONSHADOWProgramHandle, "ProjectionMatrix"); 
	if( location_projection_matrix_texture >= 0 ){
		glUniformMatrix4fv( location_projection_matrix_texture, 1, GL_FALSE, &projection_matrix[0][0]);
	} else {
		cerr << "Error al bindear ProjectionMatrix" << endl;
	}

	

	// Bind Light Settings
	glm::vec4 light_position_texture = glm::vec4( lightPos, 1.0f );
	float uniformLight = 1.7f;
	glm::vec3 light_intensity_texture = glm::vec3( uniformLight,uniformLight,uniformLight );
	glm::vec3 diffuse_reflectivity_texture = glm::vec3( 1.0f, 1.0f, 1.0f );

	GLuint location_light_position_texture = glGetUniformLocation( this->normalMappingNONSHADOWProgramHandle, "LightPosition"); 
	if( location_light_position_texture >= 0 )
		glUniform4fv( location_light_position_texture, 1, &light_position_texture[0]);

	GLuint location_light_intensity_texture = glGetUniformLocation( this->normalMappingNONSHADOWProgramHandle, "Ld"); 
	if( location_light_intensity_texture >= 0 )
		glUniform3fv( location_light_intensity_texture, 1, &light_intensity_texture[0]);

	GLuint diffuse_reflectivity_location_texture = glGetUniformLocation( this->normalMappingNONSHADOWProgramHandle, "Kd"); 
	if( diffuse_reflectivity_location_texture >= 0 )
		glUniform3fv( diffuse_reflectivity_location_texture, 1, &diffuse_reflectivity_texture[0]);
	
}

void myWindow::initNormalMapShaderParams(vec3 lightPos, mat4 projection_matrix, mat4 model_matrix){
	// Bind View Matrix
	GLuint location_view_matrix_texture = glGetUniformLocation( this->normalMappingProgramHandle, "ViewMatrix"); 
	if( location_view_matrix_texture >= 0 ){
		glUniformMatrix4fv( location_view_matrix_texture, 1, GL_FALSE, &view_matrix[0][0]);
	} else {
		cerr << "Error al bindear ViewMatrix" << endl;
	}

	// Bind View MAtrix
	GLuint location_projection_matrix_texture = glGetUniformLocation( this->normalMappingProgramHandle, "ProjectionMatrix"); 
	if( location_projection_matrix_texture >= 0 ){
		glUniformMatrix4fv( location_projection_matrix_texture, 1, GL_FALSE, &projection_matrix[0][0]);
	} else {
		cerr << "Error al bindear ProjectionMatrix" << endl;
	}

	

	// Bind Light Settings
	glm::vec4 light_position_texture = glm::vec4( lightPos, 1.0f );
	float uniformLight = 1.7f;
	glm::vec3 light_intensity_texture = glm::vec3( uniformLight,uniformLight,uniformLight );
	glm::vec3 diffuse_reflectivity_texture = glm::vec3( 1.0f, 1.0f, 1.0f );

	GLuint location_light_position_texture = glGetUniformLocation( this->normalMappingProgramHandle, "LightPosition"); 
	if( location_light_position_texture >= 0 )
		glUniform4fv( location_light_position_texture, 1, &light_position_texture[0]);

	GLuint location_light_intensity_texture = glGetUniformLocation( this->normalMappingProgramHandle, "Ld"); 
	if( location_light_intensity_texture >= 0 )
		glUniform3fv( location_light_intensity_texture, 1, &light_intensity_texture[0]);

	GLuint diffuse_reflectivity_location_texture = glGetUniformLocation( this->normalMappingProgramHandle, "Kd"); 
	if( diffuse_reflectivity_location_texture >= 0 )
		glUniform3fv( diffuse_reflectivity_location_texture, 1, &diffuse_reflectivity_texture[0]);
	
}

void myWindow::renderTexturedObjects(mat4 model_matrix_grid,bool firstPass){
	//Rendering surfaces
	if (shadows)
		if (firstPass) 
			glUseProgram(shadowProgramHandle);
	glm::mat4 m = model_matrix_grid;
	m = glm::translate(m , glm::vec3(10.0f,10.0f,0.0f));
	
	glm::mat4 woods = m;
	woods = glm::scale(woods, glm::vec3(2.0f,2.0f,2.0f));
	renderTree(woods, "Tree 0");
	woods = glm::translate(woods , glm::vec3(2.0f,3.0f,0.0f));
	renderTree(woods, "Tree 0");
	woods = glm::translate(woods , glm::vec3(1.7f,2.4f,0.0f));
	renderTree(woods, "Tree 0");
	woods = glm::translate(woods , glm::vec3(5.0f,0.7f,0.0f));
	renderTree(woods, "Tree 0");
	woods = glm::translate(woods , glm::vec3(-2.0f,-3.0f,0.0f));
	renderTree(woods, "Tree 0");
	woods = glm::translate(woods , glm::vec3(-7.0f,-0.7f,0.0f));
	renderTree(woods, "Tree 0");

	// Rendering Building.
	renderBuilding(model_matrix_grid,9,firstPass);
	
	// Render mound of sand.
	glm::mat4 mat;
	mat = glm::translate(m , glm::vec3(-5.0f,20.0f,0.0f));
	mat = scale(mat,vec3(3.0,3.0,3.0));
	this->renderPilaDeArena(mat, "textures/sand.png");

	// Render mound of dirt.
	mat = glm::translate(m , glm::vec3(10.0f,18.0f,0.0f));
	mat = scale(mat,vec3(2.0,2.0,2.0));
	this->renderPilaDeArena(mat, "textures/dirt.png");

	// Rendering Crane.
	model_matrix_grid = glm::translate(model_matrix_grid, glm::vec3(0.0f,5.0f,0.0f));
	addCraneAngle(craneAngleSpeed);
	initTexture(texMet);
	renderCrane(model_matrix_grid,17,13,4);

}

int cont = 0;


bool primeraVez = true;


void myWindow::renderWithShadows(float lightX, float lightY,float lightZ, mat4 model_matrix_grid, mat4 projection_matrix){

	if (cambioEscena){
		renderShadowsToTexture(vec3(lightX,lightY,lightZ),model_matrix_grid);
	}
	else{ 
		if (primeraVez){
			renderShadowsToTexture(vec3(lightX,lightY,lightZ),model_matrix_grid);
			primeraVez = false;
		}

	}

	glUseProgram(this->normalMappingProgramHandle);
	int loc2 = glGetUniformLocation(this->normalMappingProgramHandle, "shadowMap");
	glUniform1i(loc2, 1);
	initNormalMapShaderParams(vec3(lightX,lightY,lightZ),projection_matrix, model_matrix_grid);
	
	//Textures
	glUseProgram(textureProgramHandle);

	//Bind the generated shadow map
	glActiveTexture(GL_TEXTURE1);
	int loc = glGetUniformLocation(this->textureProgramHandle, "shadowMap");
	glUniform1i(loc, 1);
	
	initTextureShaderParams(vec3(lightX,lightY,lightZ),projection_matrix, model_matrix_grid);
	//initDepthTexture();
	computeDepthMVP(vec3(lightX,lightY,lightZ),model_matrix_grid,vec3 ( lookAtX, lookAtY, lookAtZ));
	/**        Rendering textured objects          **/

	glm::mat4 m;
	glm::mat4 floor_matrix;

	// Render ground and skybox.
	floor_matrix = glm::translate(glm::vec3(100.0f,100.0f,100.0f));
	floor_matrix = glm::scale(floor_matrix, glm::vec3(300.0f,300.0f,300.0f));
	renderGround(floor_matrix);
	
	this->renderObjectsForShadowing(model_matrix_grid,false);
	
	glUseProgram(textureNONSHADOWProgramHandle);
	initTextureNONSHADOWShaderParams(vec3(lightX,lightY,lightZ),projection_matrix, model_matrix_grid);
	renderSkyBox(floor_matrix);

	m = glm::translate(model_matrix_grid, glm::vec3(-8.5,3.2, 0.0f));
	m = glm::scale(m, glm::vec3(0.7, 0.5, 0.70));
	renderPane(m, false);
	renderPane(m, true);

	glutSwapBuffers();

}

void myWindow::renderWithoutShadows(float lightX, float lightY,float lightZ, mat4 model_matrix_grid, mat4 projection_matrix){

	glBindFramebuffer(GL_FRAMEBUFFER,0);

	glUseProgram(normalMappingNONSHADOWProgramHandle);
	initNormalMapNONSHADOWShaderParams(vec3(lightX,lightY,lightZ),projection_matrix, model_matrix_grid);

	glUseProgram(specularNONSHADOWProgramHandle);
	initSpecularNONSHADOWShaderParams(vec3(lightX,lightY,lightZ),projection_matrix, model_matrix_grid);

	//Textures
	glUseProgram(textureNONSHADOWProgramHandle);
	initTextureNONSHADOWShaderParams(vec3(lightX,lightY,lightZ),projection_matrix, model_matrix_grid);
	

	
	// Render ground and skybox.
	glm::mat4 floor_matrix = glm::translate(glm::vec3(100.0f,100.0f,100.0f));
	floor_matrix = glm::scale(floor_matrix, glm::vec3(300.0f,300.0f,300.0f));
	renderGround(floor_matrix);	

	mat4 m = glm::translate(model_matrix_grid, glm::vec3(-8.5,3.2, 0.0f));
	m = glm::scale(m, glm::vec3(0.7, 0.5, 0.70));
	renderPane(m, false);
	renderPane(m, true);
	this->renderTexturedObjects(model_matrix_grid,false);
	renderSkyBox(floor_matrix);

	
	glutSwapBuffers();
}

void myWindow::OnRender()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glClearColor(0.5,0.5,0.5,1.0);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    glEnable(GL_DEPTH_TEST);
	this->setUpCamera();
    
	// Positioning far from (0,0)
    changeObjectColor(0.5, 0.5, 0.5);
    glm::mat4 model_matrix_grid = glm::mat4 ( 1.0f );
	model_matrix_grid = glm::translate(model_matrix_grid, glm::vec3(100.0f,100.0f,100.1f));
	model_matrix_grid = glm::scale(model_matrix_grid, glm::vec3(0.5f,0.5f,0.5f));
		
	// Projection Matrix
    glm::mat4 projection_matrix = glm::mat4 ( 1.0f );
    projection_matrix = glm::infinitePerspective( 52.0f , (float)this->width / (float)this->height, 0.1f);

	float uniformLight = 1.0f;
	float lightX = 120.0f;
	float lightY = 120.0f;
	float lightZ = 120.0f;
	

	if (shadows)
		renderWithShadows(lightX,lightY,lightZ,model_matrix_grid,projection_matrix);
	else
		renderWithoutShadows(lightX,lightY,lightZ,model_matrix_grid,projection_matrix);
	

}

void  myWindow::OnIdle()
{
	this->OnRender();
}

mat4 computeLightViewMatrix(vec3 lightPos){
	vec3 lightInvDir(1.0,-0.8,0.5);
	return lookAt(lightPos, lightPos-lightInvDir, glm::vec3(0,1,0));

}

void myWindow::computeDepthMVP(vec3 lightPos,mat4 depthModelMatrix, vec3 eyePos){
	
	mat4 depthViewMatrix = computeLightViewMatrix(lightPos);
	mat4 proj_view = depthProjectionMatrix * depthViewMatrix;
	
	
	mat4 depthBiasMVP = biasMatrix*proj_view;

	GLuint PV_ID = glGetUniformLocation(this->textureProgramHandle, "PV");
	glUniformMatrix4fv(PV_ID, 1, GL_FALSE, &depthBiasMVP[0][0]);

	glUseProgram(this->normalMappingProgramHandle);
	GLuint PV_ID_N = glGetUniformLocation(this->normalMappingProgramHandle, "PV");
	glUniformMatrix4fv(PV_ID_N, 1, GL_FALSE, &depthBiasMVP[0][0]);
	glUseProgram(this->textureProgramHandle);
}

void myWindow::updateShadowShaderParams(vec3 lightPos){

	// Compute the MVP matrix from the light's point of view
	mat4 depthViewMatrix = computeLightViewMatrix(lightPos);
	mat4 proj_view = depthProjectionMatrix * depthViewMatrix;

	GLuint depthMatrixID=glGetUniformLocation( this->shadowProgramHandle, "PV");
	glUniformMatrix4fv(depthMatrixID, 1, GL_FALSE, &proj_view[0][0]);
	
}

/*  Method used to test the second fase 
	of shadow mapping with a previously
	loaded image
*/
void myWindow::initDepthTexture(){
	glActiveTexture(GL_TEXTURE1);

	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);		
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);		
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);		
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);		
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);		
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);
	glBindTexture(GL_TEXTURE_2D, textures["textures/depthTexture.png"]);
	int loc = glGetUniformLocation(this->textureProgramHandle, "shadowMap");
	glUniform1i(loc, 1);
}


void myWindow::initShadows(){
	glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer);
	glActiveTexture(GL_TEXTURE1);
	glGenTextures(1, &depthTexture);
	glBindTexture(GL_TEXTURE_2D, depthTexture);

	glTexImage2D(GL_TEXTURE_2D, 0,GL_DEPTH_COMPONENT16, shadowMapWidth, shadowMapHeight, 0,GL_DEPTH_COMPONENT, GL_FLOAT, 0);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);		
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);		
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);		
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);		
	

	glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, depthTexture, 0);

	glDrawBuffer(GL_NONE); // No color buffer is drawn to.

	// Always check that our framebuffer is ok
	if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
		cout<<"error en el framebuffer"<<endl;

}


void myWindow::renderShadowsToTexture(vec3 lightDir, mat4 model_matrix){

	glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer);
	firstPass = true;
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);


	glViewport(0,0,shadowMapWidth,shadowMapHeight);
	glUseProgram(shadowProgramHandle);
	updateShadowShaderParams(lightDir);

	renderObjectsForShadowing(model_matrix,true);

	glBindFramebuffer(GL_FRAMEBUFFER,0);
	firstPass=false;

	glViewport(0,0,width,height);
}


void myWindow::renderObjectsForShadowing(mat4 model_matrix,bool firstPass){
	this->renderTexturedObjects(model_matrix, firstPass);
}

void myWindow::resetCamera() {
	//Camera
	cameraEyeX=121.0;
	cameraEyeY=120.0;
	cameraEyeZ=105.0;

	cameraEyeXSpeed=0.0;
	cameraEyeYSpeed=0.0;
	cameraEyeZSpeed=0.0;

	scrollMargin=100.0;
	zScrollSpeed = 0.0;
	yScrollSpeed = 0.0;
	xScrollSpeed = 0.0;

	lookAtZ=90.0;
	lookAtY=90.0;
	lookAtX=100.0;
	
	orbitCenterX = 100.0f;
	orbitCenterY = 100.0f;
	orbitCenterZ = 100.0f;

	orbitRadius = 10.0f;
	orbitHeight = 120.0f;

	cameraTheeta = -120.0f;
	cameraTheetaSpeed = cameraPhi = cameraPhiSpeed = 0.0;
}

void myWindow::compileStandardShaders(){
	// Load vertex Shader
	this->vertShader = glCreateShader (GL_VERTEX_SHADER);
	if ( 0 == this->vertShader )
	{
		cout << "Error creating vertex shader" << endl;
	}

	ifstream v_shader_file("DiffuseShadingVShader.vert", ifstream::in);
	string v_str((istreambuf_iterator<char>(v_shader_file)), istreambuf_iterator<char>());
	const char* vs_code_array[] = {v_str.c_str()};

	glShaderSource( this->vertShader, 1, vs_code_array, NULL);

	// Compilar el shader
	glCompileShader( this->vertShader );

	// verificar resultado de la compilacion
	GLint vs_compilation_result;
	glGetShaderiv( this->vertShader, GL_COMPILE_STATUS, &vs_compilation_result );
	if( GL_FALSE == vs_compilation_result )
	{
		cout << "Vertex shader compilation failed!\n" << endl;
		GLint logLen;
		glGetShaderiv( this->vertShader, GL_INFO_LOG_LENGTH, &logLen );
		if( logLen > 0 )
		{
			char * log = (char *)malloc(logLen);
			GLsizei written;
			glGetShaderInfoLog(vertShader, logLen, &written, log);
			cout << "Shader log: " << log << endl;
			free(log);
		}
	}

	// Load fragment Shader
	this->fragShader = glCreateShader (GL_FRAGMENT_SHADER);
	if ( 0 == this->fragShader )
	{
		cout << "Error creating fragment shader" << endl;
	}

	ifstream f_shader_file("DiffuseShadingFShader.frag", ifstream::in);
	string f_str((istreambuf_iterator<char>(f_shader_file)), istreambuf_iterator<char>());
	const char* fs_code_array[] = {f_str.c_str()};

	glShaderSource( this->fragShader, 1, fs_code_array, NULL);

	// Compilar el shader
	glCompileShader( this->fragShader );

	// verificar resultado de la compilacion
	GLint fs_compilation_result;
	glGetShaderiv( this->fragShader, GL_COMPILE_STATUS, &fs_compilation_result );
	if( GL_FALSE == fs_compilation_result )
	{
		cout << "Fragment shader compilation failed!\n" << endl;
		GLint logLen;
		glGetShaderiv( this->fragShader, GL_INFO_LOG_LENGTH, &logLen );
		if( logLen > 0 )
		{
			char * log = (char *)malloc(logLen);
			GLsizei written;
			glGetShaderInfoLog( this->fragShader, logLen, &written, log);
			cout << "Shader log: " << log << endl;
			free(log);
		}
	}


}

void myWindow::compileTextureShaders(){
	// Begin Load texture vertex shader.
	//
	this->textureVertShader = glCreateShader (GL_VERTEX_SHADER);
	if ( 0 == this->textureVertShader )
	{
		cout << "Error creating texture vertex shader" << endl;
	}

	ifstream v_shader_texture_file("TexturingAndDiffuseShadingVShader.vert", ifstream::in);
	string v_str_texture((istreambuf_iterator<char>(v_shader_texture_file)), istreambuf_iterator<char>());
	const char* vs_code_array_texture[] = {v_str_texture.c_str()};

	glShaderSource( this->textureVertShader, 1, vs_code_array_texture, NULL);

	// Compilar el shader
	glCompileShader( this->textureVertShader );

	// verificar resultado de la compilacion
	GLint vs_compilation_result_texture;
	glGetShaderiv( this->textureVertShader, GL_COMPILE_STATUS, &vs_compilation_result_texture );
	if( GL_FALSE == vs_compilation_result_texture )
	{
		cout << "Texture Vertex shader compilation failed!\n" << endl;
		GLint logLen;
		glGetShaderiv( this->textureVertShader, GL_INFO_LOG_LENGTH, &logLen );
		if( logLen > 0 )
		{
			char * log = (char *)malloc(logLen);
			GLsizei written;
			glGetShaderInfoLog(textureVertShader, logLen, &written, log);
			cout << "Shader log: " << log << endl;
			free(log);
		}
	}

	//
	// End loading texture vertex shader.
	/*******************************************/


	// Load texture fragment Shader
	this->textureFragShader = glCreateShader (GL_FRAGMENT_SHADER);
	if ( 0 == this->textureFragShader )
	{
		cout << "Error creating texture fragment shader" << endl;
	}

	ifstream tf_shader_file("TexturingAndDiffuseShadingFShader.frag", ifstream::in);
	string tf_str((istreambuf_iterator<char>(tf_shader_file)), istreambuf_iterator<char>());
	const char* tfs_code_array[] = {tf_str.c_str()};

	glShaderSource( this->textureFragShader, 1, tfs_code_array, NULL);

	// Compilar el shader
	glCompileShader( this->textureFragShader );

	// verificar resultado de la compilacion
	GLint tfs_compilation_result;
	glGetShaderiv( this->textureFragShader, GL_COMPILE_STATUS, &tfs_compilation_result );
	if( GL_FALSE == tfs_compilation_result )
	{
		cout << "Fragment shader compilation failed!\n" << endl;
		GLint logLen;
		glGetShaderiv( this->textureFragShader, GL_INFO_LOG_LENGTH, &logLen );
		if( logLen > 0 )
		{
			char * log = (char *)malloc(logLen);
			GLsizei written;
			glGetShaderInfoLog( this->textureFragShader, logLen, &written, log);
			cout << "Shader log: " << log << endl;
			free(log);
		}
	}
}

void myWindow::compileShadowShaders(){
	// Begin Load texture vertex shader.
	this->shadowVertShader = glCreateShader (GL_VERTEX_SHADER);
	if ( 0 == this->shadowVertShader )
	{
		cout << "Error creating shadow vertex shader" << endl;
	}

	ifstream v_shader_shadow_file("shadowMapV.vert", ifstream::in);
	string v_str_shadow((istreambuf_iterator<char>(v_shader_shadow_file)), istreambuf_iterator<char>());
	const char* vs_code_array_shadow[] = {v_str_shadow.c_str()};

	glShaderSource( this->shadowVertShader, 1, vs_code_array_shadow, NULL);

	// Compilar el shader
	glCompileShader( this->shadowVertShader );

	// verificar resultado de la compilacion
	GLint vs_compilation_result_shadow;
	glGetShaderiv( this->shadowVertShader, GL_COMPILE_STATUS, &vs_compilation_result_shadow );
	if( GL_FALSE == vs_compilation_result_shadow )
	{
		cout << "shadow Vertex shader compilation failed!\n" << endl;
		GLint logLen;
		glGetShaderiv( this->shadowVertShader, GL_INFO_LOG_LENGTH, &logLen );
		if( logLen > 0 )
		{
			char * log = (char *)malloc(logLen);
			GLsizei written;
			glGetShaderInfoLog(shadowVertShader, logLen, &written, log);
			cout << "Shader log: " << log << endl;
			free(log);
		}
	}

	// End loading shadow vertex shader.


	// Load shadow fragment Shader
	this->shadowFragShader = glCreateShader (GL_FRAGMENT_SHADER);
	if ( 0 == this->shadowFragShader )
	{
		cout << "Error creating shadow fragment shader" << endl;
	}

	ifstream tf_shader_file("shadowMapF.frag", ifstream::in);
	string tf_str((istreambuf_iterator<char>(tf_shader_file)), istreambuf_iterator<char>());
	const char* tfs_code_array[] = {tf_str.c_str()};

	glShaderSource( this->shadowFragShader, 1, tfs_code_array, NULL);

	// Compilar el shader
	glCompileShader( this->shadowFragShader );

	// verificar resultado de la compilacion
	GLint tfs_compilation_result;
	glGetShaderiv( this->shadowFragShader, GL_COMPILE_STATUS, &tfs_compilation_result );
	if( GL_FALSE == tfs_compilation_result )
	{
		cout << "Fragment shader compilation failed!\n" << endl;
		GLint logLen;
		glGetShaderiv( this->shadowFragShader, GL_INFO_LOG_LENGTH, &logLen );
		if( logLen > 0 )
		{
			char * log = (char *)malloc(logLen);
			GLsizei written;
			glGetShaderInfoLog( this->shadowFragShader, logLen, &written, log);
			cout << "Shader log: " << log << endl;
			free(log);
		}
	}
}

void myWindow::compileTextureNONSHADOWShaders(){

	this->textureNONSHADOWVertShader = glCreateShader (GL_VERTEX_SHADER);
	if ( 0 == this->textureNONSHADOWVertShader )
		cout << "Error creating texture vertex shader" << endl;

	ifstream v_shader_texture_file("TextureNONSHADOW.vert", ifstream::in);
	string v_str_texture((istreambuf_iterator<char>(v_shader_texture_file)), istreambuf_iterator<char>());
	const char* vs_code_array_texture[] = {v_str_texture.c_str()};

	glShaderSource( this->textureNONSHADOWVertShader, 1, vs_code_array_texture, NULL);

	// Compilar el shader
	glCompileShader( this->textureNONSHADOWVertShader );

	// verificar resultado de la compilacion
	GLint vs_compilation_result_texture;
	glGetShaderiv( this->textureNONSHADOWVertShader, GL_COMPILE_STATUS, &vs_compilation_result_texture );
	if( GL_FALSE == vs_compilation_result_texture )
	{
		cout << "Texture Vertex shader compilation failed!\n" << endl;
		GLint logLen;
		glGetShaderiv( this->textureNONSHADOWVertShader, GL_INFO_LOG_LENGTH, &logLen );
		if( logLen > 0 )
		{
			char * log = (char *)malloc(logLen);
			GLsizei written;
			glGetShaderInfoLog(textureNONSHADOWVertShader, logLen, &written, log);
			cout << "Shader log: " << log << endl;
			free(log);
		}
	}

	//
	// End loading texture vertex shader.
	/*******************************************/


	// Load texture fragment Shader
	this->textureNONSHADOWFragShader = glCreateShader (GL_FRAGMENT_SHADER);
	if ( 0 == this->textureNONSHADOWFragShader )
	{
		cout << "Error creating texture fragment shader" << endl;
	}

	ifstream tf_shader_file("TextureNONSHADOW.frag", ifstream::in);
	string tf_str((istreambuf_iterator<char>(tf_shader_file)), istreambuf_iterator<char>());
	const char* tfs_code_array[] = {tf_str.c_str()};

	glShaderSource( this->textureNONSHADOWFragShader, 1, tfs_code_array, NULL);

	// Compilar el shader
	glCompileShader( this->textureNONSHADOWFragShader );

	// verificar resultado de la compilacion
	GLint tfs_compilation_result;
	glGetShaderiv( this->textureNONSHADOWFragShader, GL_COMPILE_STATUS, &tfs_compilation_result );
	if( GL_FALSE == tfs_compilation_result )
	{
		cout << "Fragment shader compilation failed!\n" << endl;
		GLint logLen;
		glGetShaderiv( this->textureNONSHADOWFragShader, GL_INFO_LOG_LENGTH, &logLen );
		if( logLen > 0 )
		{
			char * log = (char *)malloc(logLen);
			GLsizei written;
			glGetShaderInfoLog( this->textureNONSHADOWFragShader, logLen, &written, log);
			cout << "Shader log: " << log << endl;
			free(log);
		}
	}
}

void myWindow::compileNormalMappingNONSHADOWShaders(){

	this->normalMappingNONSHADOWVertShader = glCreateShader (GL_VERTEX_SHADER);
	if ( 0 == this->normalMappingNONSHADOWVertShader )
		cout << "Error creating normal mapping vertex shader" << endl;

	ifstream v_shader_texture_file("normalMappingNONSHADOW.vert", ifstream::in);
	string v_str_texture((istreambuf_iterator<char>(v_shader_texture_file)), istreambuf_iterator<char>());
	const char* vs_code_array_texture[] = {v_str_texture.c_str()};

	glShaderSource( this->normalMappingNONSHADOWVertShader, 1, vs_code_array_texture, NULL);

	// Compilar el shader
	glCompileShader( this->normalMappingNONSHADOWVertShader );

	// verificar resultado de la compilacion
	GLint vs_compilation_result_texture;
	glGetShaderiv( this->normalMappingNONSHADOWVertShader, GL_COMPILE_STATUS, &vs_compilation_result_texture );
	if( GL_FALSE == vs_compilation_result_texture )
	{
		cout << "Normal Mapping Vertex shader compilation failed!\n" << endl;
		GLint logLen;
		glGetShaderiv( this->normalMappingNONSHADOWVertShader, GL_INFO_LOG_LENGTH, &logLen );
		if( logLen > 0 )
		{
			char * log = (char *)malloc(logLen);
			GLsizei written;
			glGetShaderInfoLog(normalMappingNONSHADOWVertShader, logLen, &written, log);
			cout << "Shader log: " << log << endl;
			free(log);
		}
	}

	//
	// End loading texture vertex shader.
	/*******************************************/


	// Load texture fragment Shader
	this->normalMappingNONSHADOWFragShader = glCreateShader (GL_FRAGMENT_SHADER);
	if ( 0 == this->normalMappingNONSHADOWFragShader )
	{
		cout << "Error creating normal mapping fragment shader" << endl;
	}

	ifstream tf_shader_file("normalMappingNONSHADOW.frag", ifstream::in);
	string tf_str((istreambuf_iterator<char>(tf_shader_file)), istreambuf_iterator<char>());
	const char* tfs_code_array[] = {tf_str.c_str()};

	glShaderSource( this->normalMappingNONSHADOWFragShader, 1, tfs_code_array, NULL);

	// Compilar el shader
	glCompileShader( this->normalMappingNONSHADOWFragShader );

	// verificar resultado de la compilacion
	GLint tfs_compilation_result;
	glGetShaderiv( this->normalMappingNONSHADOWFragShader, GL_COMPILE_STATUS, &tfs_compilation_result );
	if( GL_FALSE == tfs_compilation_result )
	{
		cout << "Normal Mapping Fragment shader compilation failed!\n" << endl;
		GLint logLen;
		glGetShaderiv( this->normalMappingNONSHADOWFragShader, GL_INFO_LOG_LENGTH, &logLen );
		if( logLen > 0 )
		{
			char * log = (char *)malloc(logLen);
			GLsizei written;
			glGetShaderInfoLog( this->normalMappingNONSHADOWFragShader, logLen, &written, log);
			cout << "Shader log: " << log << endl;
			free(log);
		}
	}
}

void myWindow::compileNormalMappingShaders(){

	this->normalMappingVertShader = glCreateShader (GL_VERTEX_SHADER);
	if ( 0 == this->normalMappingVertShader )
		cout << "Error creating normal mapping vertex shader" << endl;

	ifstream v_shader_texture_file("normalMapping.vert", ifstream::in);
	string v_str_texture((istreambuf_iterator<char>(v_shader_texture_file)), istreambuf_iterator<char>());
	const char* vs_code_array_texture[] = {v_str_texture.c_str()};

	glShaderSource( this->normalMappingVertShader, 1, vs_code_array_texture, NULL);

	// Compilar el shader
	glCompileShader( this->normalMappingVertShader );

	// verificar resultado de la compilacion
	GLint vs_compilation_result_texture;
	glGetShaderiv( this->normalMappingVertShader, GL_COMPILE_STATUS, &vs_compilation_result_texture );
	if( GL_FALSE == vs_compilation_result_texture )
	{
		cout << "Normal Mapping Vertex shader compilation failed!\n" << endl;
		GLint logLen;
		glGetShaderiv( this->normalMappingVertShader, GL_INFO_LOG_LENGTH, &logLen );
		if( logLen > 0 )
		{
			char * log = (char *)malloc(logLen);
			GLsizei written;
			glGetShaderInfoLog(normalMappingVertShader, logLen, &written, log);
			cout << "Shader log: " << log << endl;
			free(log);
		}
	}

	//
	// End loading texture vertex shader.
	/*******************************************/


	// Load texture fragment Shader
	this->normalMappingFragShader = glCreateShader (GL_FRAGMENT_SHADER);
	if ( 0 == this->normalMappingFragShader )
	{
		cout << "Error creating normal mapping fragment shader" << endl;
	}

	ifstream tf_shader_file("normalMapping.frag", ifstream::in);
	string tf_str((istreambuf_iterator<char>(tf_shader_file)), istreambuf_iterator<char>());
	const char* tfs_code_array[] = {tf_str.c_str()};

	glShaderSource( this->normalMappingFragShader, 1, tfs_code_array, NULL);

	// Compilar el shader
	glCompileShader( this->normalMappingFragShader );

	// verificar resultado de la compilacion
	GLint tfs_compilation_result;
	glGetShaderiv( this->normalMappingFragShader, GL_COMPILE_STATUS, &tfs_compilation_result );
	if( GL_FALSE == tfs_compilation_result )
	{
		cout << "Normal Mapping Fragment shader compilation failed!\n" << endl;
		GLint logLen;
		glGetShaderiv( this->normalMappingFragShader, GL_INFO_LOG_LENGTH, &logLen );
		if( logLen > 0 )
		{
			char * log = (char *)malloc(logLen);
			GLsizei written;
			glGetShaderInfoLog( this->normalMappingFragShader, logLen, &written, log);
			cout << "Shader log: " << log << endl;
			free(log);
		}
	}
}

void myWindow::compileSpecularShaders(){
	// Begin Load texture vertex shader.
	this->specularVertShader = glCreateShader (GL_VERTEX_SHADER);
	if ( 0 == this->specularVertShader )
	{
		cout << "Error creating specular vertex shader" << endl;
	}

	ifstream v_shader_specular_file("specularShader.vert", ifstream::in);
	string v_str_specular((istreambuf_iterator<char>(v_shader_specular_file)), istreambuf_iterator<char>());
	const char* vs_code_array_specular[] = {v_str_specular.c_str()};

	glShaderSource( this->specularVertShader, 1, vs_code_array_specular, NULL);

	// Compilar el shader
	glCompileShader( this->specularVertShader );

	// verificar resultado de la compilacion
	GLint vs_compilation_result_specular;
	glGetShaderiv( this->specularVertShader, GL_COMPILE_STATUS, &vs_compilation_result_specular );
	if( GL_FALSE == vs_compilation_result_specular )
	{
		cout << "specular Vertex shader compilation failed!\n" << endl;
		GLint logLen;
		glGetShaderiv( this->specularVertShader, GL_INFO_LOG_LENGTH, &logLen );
		if( logLen > 0 )
		{
			char * log = (char *)malloc(logLen);
			GLsizei written;
			glGetShaderInfoLog(specularVertShader, logLen, &written, log);
			cout << "Shader log: " << log << endl;
			free(log);
		}
	}

	// End loading specular vertex shader.


	// Load specular fragment Shader
	this->specularFragShader = glCreateShader (GL_FRAGMENT_SHADER);
	if ( 0 == this->specularFragShader )
	{
		cout << "Error creating specular fragment shader" << endl;
	}

	ifstream tf_shader_file("specularShader.frag", ifstream::in);
	string tf_str((istreambuf_iterator<char>(tf_shader_file)), istreambuf_iterator<char>());
	const char* tfs_code_array[] = {tf_str.c_str()};

	glShaderSource( this->specularFragShader, 1, tfs_code_array, NULL);

	// Compilar el shader
	glCompileShader( this->specularFragShader );

	// verificar resultado de la compilacion
	GLint tfs_compilation_result;
	glGetShaderiv( this->specularFragShader, GL_COMPILE_STATUS, &tfs_compilation_result );
	if( GL_FALSE == tfs_compilation_result )
	{
		cout << "Fragment shader compilation failed!\n" << endl;
		GLint logLen;
		glGetShaderiv( this->specularFragShader, GL_INFO_LOG_LENGTH, &logLen );
		if( logLen > 0 )
		{
			char * log = (char *)malloc(logLen);
			GLsizei written;
			glGetShaderInfoLog( this->specularFragShader, logLen, &written, log);
			cout << "Shader log: " << log << endl;
			free(log);
		}
	}
}

void myWindow::complieSpecularNONSHADOWShaders(){
// Begin Load texture vertex shader.
	this->specularNONSHADOWVertShader = glCreateShader (GL_VERTEX_SHADER);
	if ( 0 == this->specularNONSHADOWVertShader )
	{
		cout << "Error creating specularNONSHADOW vertex shader" << endl;
	}

	ifstream v_shader_specularNONSHADOW_file("SpecularNOSHADOW.vect", ifstream::in);
	string v_str_specularNONSHADOW((istreambuf_iterator<char>(v_shader_specularNONSHADOW_file)), istreambuf_iterator<char>());
	const char* vs_code_array_specularNONSHADOW[] = {v_str_specularNONSHADOW.c_str()};

	glShaderSource( this->specularNONSHADOWVertShader, 1, vs_code_array_specularNONSHADOW, NULL);

	// Compilar el shader
	glCompileShader( this->specularNONSHADOWVertShader );

	// verificar resultado de la compilacion
	GLint vs_compilation_result_specularNONSHADOW;
	glGetShaderiv( this->specularNONSHADOWVertShader, GL_COMPILE_STATUS, &vs_compilation_result_specularNONSHADOW );
	if( GL_FALSE == vs_compilation_result_specularNONSHADOW )
	{
		cout << "specularNONSHADOW Vertex shader compilation failed!\n" << endl;
		GLint logLen;
		glGetShaderiv( this->specularNONSHADOWVertShader, GL_INFO_LOG_LENGTH, &logLen );
		if( logLen > 0 )
		{
			char * log = (char *)malloc(logLen);
			GLsizei written;
			glGetShaderInfoLog(specularNONSHADOWVertShader, logLen, &written, log);
			cout << "Shader log: " << log << endl;
			free(log);
		}
	}

	// End loading specularNONSHADOW vertex shader.


	// Load specularNONSHADOW fragment Shader
	this->specularNONSHADOWFragShader = glCreateShader (GL_FRAGMENT_SHADER);
	if ( 0 == this->specularNONSHADOWFragShader )
	{
		cout << "Error creating specularNONSHADOW fragment shader" << endl;
	}

	ifstream tf_shader_file("SpecularNOSHADOW.frag", ifstream::in);
	string tf_str((istreambuf_iterator<char>(tf_shader_file)), istreambuf_iterator<char>());
	const char* tfs_code_array[] = {tf_str.c_str()};

	glShaderSource( this->specularNONSHADOWFragShader, 1, tfs_code_array, NULL);

	// Compilar el shader
	glCompileShader( this->specularNONSHADOWFragShader );

	// verificar resultado de la compilacion
	GLint tfs_compilation_result;
	glGetShaderiv( this->specularNONSHADOWFragShader, GL_COMPILE_STATUS, &tfs_compilation_result );
	if( GL_FALSE == tfs_compilation_result )
	{
		cout << "Fragment shader compilation failed!\n" << endl;
		GLint logLen;
		glGetShaderiv( this->specularNONSHADOWFragShader, GL_INFO_LOG_LENGTH, &logLen );
		if( logLen > 0 )
		{
			char * log = (char *)malloc(logLen);
			GLsizei written;
			glGetShaderInfoLog( this->specularNONSHADOWFragShader, logLen, &written, log);
			cout << "Shader log: " << log << endl;
			free(log);
		}
	}
}

void myWindow::linkStandardShaders(){
	this->programHandle = glCreateProgram();
	if ( 0 == this->programHandle ){
		cout << "Error creating program object" << endl;
	}
	else
	{
		glAttachShader( this->programHandle, this->vertShader );
		glAttachShader( this->programHandle, this->fragShader );

		glLinkProgram( this->programHandle );

		GLint status;
		glGetProgramiv( this->programHandle, GL_LINK_STATUS, &status );
		if( GL_FALSE == status )
		{
			cout << "Failed to link shader program!\n" << endl;
			GLint logLen;
			glGetProgramiv( this->programHandle, GL_INFO_LOG_LENGTH, &logLen);
			if( logLen > 0 )
			{
				char * log = (char *)malloc(logLen);
				GLsizei written;
				glGetProgramInfoLog(programHandle, logLen, &written, log);
				cout << "Program log: " << log << endl;
				free(log);
			}
		}
	}

}

void myWindow::linkTextureShaders(){
	this->textureProgramHandle = glCreateProgram();
	if ( 0 == this->textureProgramHandle )
	{
		cout << "Error creating program object" << endl;
	}
	else
	{
		glAttachShader( this->textureProgramHandle, this->textureVertShader );
		glAttachShader( this->textureProgramHandle, this->textureFragShader );

		glLinkProgram( this->textureProgramHandle );

		GLint status;
		glGetProgramiv( this->textureProgramHandle, GL_LINK_STATUS, &status );
		if( GL_FALSE == status )
		{
			cout << "Failed to link shader program!\n" << endl;
			GLint logLen;
			glGetProgramiv( this->textureProgramHandle, GL_INFO_LOG_LENGTH, &logLen);
			if( logLen > 0 )
			{
				char * log = (char *)malloc(logLen);
				GLsizei written;
				glGetProgramInfoLog(textureProgramHandle, logLen, &written, log);
				cout << "Program log: \n" << log << endl;
				getchar();
				free(log);
			}
		}
	}

}

void myWindow::linkShadowShaders(){
	this->shadowProgramHandle = glCreateProgram();
	if ( 0 == this->shadowProgramHandle )
	{
		cout << "Error creating program object" << endl;
	}
	else
	{
		glAttachShader( this->shadowProgramHandle, this->shadowVertShader );
		glAttachShader( this->shadowProgramHandle, this->shadowFragShader );

		glLinkProgram( this->shadowProgramHandle );

		GLint status;
		glGetProgramiv( this->shadowProgramHandle, GL_LINK_STATUS, &status );
		if( GL_FALSE == status )
		{
			cout << "Failed to link shader program!\n" << endl;
			GLint logLen;
			glGetProgramiv( this->shadowProgramHandle, GL_INFO_LOG_LENGTH, &logLen);
			if( logLen > 0 )
			{
				char * log = (char *)malloc(logLen);
				GLsizei written;
				glGetProgramInfoLog(shadowProgramHandle, logLen, &written, log);
				cout << "Program log: \n" <<log << endl;
				free(log);
			}
		}
	}


}

void myWindow::linkTextureNONSHADOWShaders(){
	this->textureNONSHADOWProgramHandle = glCreateProgram();
	if ( 0 == this->textureNONSHADOWProgramHandle )
	{
		cout << "Error creating program object" << endl;
	}
	else
	{
		glAttachShader( this->textureNONSHADOWProgramHandle, this->textureNONSHADOWVertShader );
		glAttachShader( this->textureNONSHADOWProgramHandle, this->textureNONSHADOWFragShader );

		glLinkProgram( this->textureNONSHADOWProgramHandle );

		GLint status;
		glGetProgramiv( this->textureNONSHADOWProgramHandle, GL_LINK_STATUS, &status );
		if( GL_FALSE == status )
		{
			cout << "Failed to link shader program!\n" << endl;
			GLint logLen;
			glGetProgramiv( this->textureNONSHADOWProgramHandle, GL_INFO_LOG_LENGTH, &logLen);
			if( logLen > 0 )
			{
				char * log = (char *)malloc(logLen);
				GLsizei written;
				glGetProgramInfoLog(textureNONSHADOWProgramHandle, logLen, &written, log);
				cout << "Program log: \n" << log << endl;
				getchar();
				free(log);
			}
		}
	}

}

void myWindow::linkNormalMappingNONSHADOWShaders(){
	this->normalMappingNONSHADOWProgramHandle = glCreateProgram();
	if ( 0 == this->normalMappingNONSHADOWProgramHandle )
	{
		cout << "Error creating program object" << endl;
	}
	else
	{
		glAttachShader( this->normalMappingNONSHADOWProgramHandle, this->normalMappingNONSHADOWVertShader );
		glAttachShader( this->normalMappingNONSHADOWProgramHandle, this->normalMappingNONSHADOWFragShader );

		glLinkProgram( this->normalMappingNONSHADOWProgramHandle );

		GLint status;
		glGetProgramiv( this->normalMappingNONSHADOWProgramHandle, GL_LINK_STATUS, &status );
		if( GL_FALSE == status )
		{
			cout << "Failed to link shader program!\n" << endl;
			GLint logLen;
			glGetProgramiv( this->normalMappingNONSHADOWProgramHandle, GL_INFO_LOG_LENGTH, &logLen);
			if( logLen > 0 )
			{
				char * log = (char *)malloc(logLen);
				GLsizei written;
				glGetProgramInfoLog(normalMappingNONSHADOWProgramHandle, logLen, &written, log);
				cout << "Program log: \n" << log << endl;
				getchar();
				free(log);
			}
		}
	}

}

void myWindow::linkNormalMappingShaders(){
	this->normalMappingProgramHandle = glCreateProgram();
	if ( 0 == this->normalMappingProgramHandle )
	{
		cout << "Error creating program object" << endl;
	}
	else
	{
		glAttachShader( this->normalMappingProgramHandle, this->normalMappingVertShader );
		glAttachShader( this->normalMappingProgramHandle, this->normalMappingFragShader );

		glLinkProgram( this->normalMappingProgramHandle );

		GLint status;
		glGetProgramiv( this->normalMappingProgramHandle, GL_LINK_STATUS, &status );
		if( GL_FALSE == status )
		{
			cout << "Failed to link shader program!\n" << endl;
			GLint logLen;
			glGetProgramiv( this->normalMappingProgramHandle, GL_INFO_LOG_LENGTH, &logLen);
			if( logLen > 0 )
			{
				char * log = (char *)malloc(logLen);
				GLsizei written;
				glGetProgramInfoLog(normalMappingProgramHandle, logLen, &written, log);
				cout << "Program log: \n" << log << endl;
				getchar();
				free(log);
			}
		}
	}

}

void myWindow::linkSpecularShaders(){
	this->specularProgramHandle = glCreateProgram();
	if ( 0 == this->specularProgramHandle )
	{
		cout << "Error creating program object" << endl;
	}
	else
	{
		glAttachShader( this->specularProgramHandle, this->specularVertShader );
		glAttachShader( this->specularProgramHandle, this->specularFragShader );

		glLinkProgram( this->specularProgramHandle );

		GLint status;
		glGetProgramiv( this->specularProgramHandle, GL_LINK_STATUS, &status );
		if( GL_FALSE == status )
		{
			cout << "Failed to link shader program!\n" << endl;
			GLint logLen;
			glGetProgramiv( this->specularProgramHandle, GL_INFO_LOG_LENGTH, &logLen);
			if( logLen > 0 )
			{
				char * log = (char *)malloc(logLen);
				GLsizei written;
				glGetProgramInfoLog(specularProgramHandle, logLen, &written, log);
				cout << "Program log: \n" << log << endl;
				free(log);
			}
		}
	}


}

void myWindow::linkSpecularNONSHADOWShaders(){
	this->specularNONSHADOWProgramHandle = glCreateProgram();
	if ( 0 == this->specularNONSHADOWProgramHandle )
	{
		cout << "Error creating program object" << endl;
	}
	else
	{
		glAttachShader( this->specularNONSHADOWProgramHandle, this->specularNONSHADOWVertShader );
		glAttachShader( this->specularNONSHADOWProgramHandle, this->specularNONSHADOWFragShader );

		glLinkProgram( this->specularNONSHADOWProgramHandle );

		GLint status;
		glGetProgramiv( this->specularNONSHADOWProgramHandle, GL_LINK_STATUS, &status );
		if( GL_FALSE == status )
		{
			cout << "Failed to link specular NOSHADOW shader program!\n" << endl;
			GLint logLen;
			glGetProgramiv( this->specularNONSHADOWProgramHandle, GL_INFO_LOG_LENGTH, &logLen);
			if( logLen > 0 )
			{
				char * log = (char *)malloc(logLen);
				GLsizei written;
				glGetProgramInfoLog(specularNONSHADOWProgramHandle, logLen, &written, log);
				cout << "Program log: \n" << log << endl;
				free(log);
			}
		}
	}

}

GLuint textureBufferHandle;
GLuint vaoHandle;

void initGLEW(){
	if (GLEW_ARB_shading_language_100) { 
		cout << "GLEW_ARB_shading_language_100" << endl;
		int major, minor, revision;
		const GLubyte* sVersion = glGetString(GL_SHADING_LANGUAGE_VERSION_ARB);
		if (glGetError() == GL_INVALID_ENUM)
		{
			major = 1; minor = 0; revision=51;
		}
		else
		{
			string version((char*)sVersion);
			cout << version.c_str() << endl;
		}

	}	
}

void  myWindow::OnInit()
{
    this->createSpiralSphere(1.0, 32, 32);
    this->createGrid(10);
    this->createCloth(50);
    this->createTriangleCloth();
    this->createCube();
    this->createCylinder();
    this->createTreeCup();
	this->cambioEscena = false;
    //Surface shit

    this->createSurfaces();


	depthProjectionMatrix = ortho<float>(-40,40,-40,40,-40,40);
	//biasMatrix = mat4(1.0);
	biasMatrix[0][0]=0.5;biasMatrix[0][1]=0.0;biasMatrix[0][2]=0.0;biasMatrix[0][3]=0.0;
	biasMatrix[1][0]=0.0;biasMatrix[1][1]=0.5;biasMatrix[1][2]=0.0;biasMatrix[1][3]=0.0;
	biasMatrix[2][0]=0.0;biasMatrix[2][1]=0.0;biasMatrix[2][2]=0.5;biasMatrix[2][3]=0.0;
	biasMatrix[3][0]=0.5;biasMatrix[3][1]=0.5;biasMatrix[3][2]=0.5;biasMatrix[3][3]=1.0;


    //Curves
    this->createCurves();
    this->createSplines();
        
    this->createSweepSurface();

    // Time reset.
    global_time = 0.0f;

    //Camera
    this->resetCamera();

	initGLEW();

	//Compile shaders
	this->compileStandardShaders();
	this->linkStandardShaders();
	if (shadows){
		this->compileSpecularShaders();
		this->compileTextureShaders();
		this->compileShadowShaders();
		this->compileNormalMappingShaders();
		this->linkTextureShaders();
		this->linkShadowShaders();
		this->linkSpecularShaders();
		this->linkNormalMappingShaders();
		this->compileTextureNONSHADOWShaders();
		this->compileNormalMappingNONSHADOWShaders();
		this->linkTextureNONSHADOWShaders();
		this->linkNormalMappingNONSHADOWShaders();
	} else {
		// Linking the shader programs
		this->compileTextureNONSHADOWShaders();
		this->compileNormalMappingNONSHADOWShaders();
		this->complieSpecularNONSHADOWShaders();
		this->linkTextureNONSHADOWShaders();
		this->linkNormalMappingNONSHADOWShaders();
		this->linkSpecularNONSHADOWShaders();
	}
	loadTextures();
	SetFullscreen(false);

	//Shadow framebuffer init

	// The framebuffer, which regroups 0, 1, or more textures, and 0 or 1 depth buffer.
	frameBuffer = 0;
	glGenFramebuffers(1, &frameBuffer);
	if (shadows) initShadows();
}

void myWindow::OnResize(int w, int h) 
{
    glViewport (0, 0, (GLsizei) w, (GLsizei) h); 
    this->width = w;
    this->height = h;
}

void  myWindow::OnClose(void)
{
}

void myWindow::OnMouseDown(int button, int x, int y)
{
}

void myWindow::OnMouseUp(int button, int x, int y)
{
}

void myWindow::OnMouseWheel(int nWheelNumber, int nDirection, int x, int y)
{
}

void myWindow::OnMouseMove(int x, int y)
{
	float speed = 2.0;
	if (x>= glutGet(GLUT_WINDOW_WIDTH)-scrollMargin){
		yScrollSpeed = speed;
		cameraTheetaSpeed = speed;
	}
	else
		if (x<= scrollMargin){
			yScrollSpeed = -speed;
			cameraTheetaSpeed = -speed;
		}
		else{
			yScrollSpeed = 0.0;
			cameraTheetaSpeed = 0.0;
		}
	if (y>= glutGet(GLUT_WINDOW_HEIGHT)-scrollMargin){
		zScrollSpeed = -speed;
		cameraPhiSpeed = -speed;
	}
	else 
		if (y<= scrollMargin){
			zScrollSpeed = speed;
			cameraPhiSpeed = speed;
		}
		else{
			zScrollSpeed = 0.0;
			cameraPhiSpeed = 0.0;
		}

	//if (cameraEyeX<0) xScrollSpeed = -xScrollSpeed;
};

void myWindow::OnLeftMouseDrag(int x, int y){
};

void myWindow::OnKeyDown(int nKey, char cAscii)
{     
	float velCamara = 0.2;
	
	float mirrorOffsetVSpeed = 0.005;
	float mirrorOffsetHSpeed = 0.005;
	if (cAscii == 27) // 0x1b = ESC
    {
        this->Close(); // Close Window!
    } 
	if (cAscii == 32) // space
    {
		mirrorOffsetV += mirrorOffsetVSpeed;
        cameraEyeZSpeed = velCamara; // 
    }
	if (cAscii == 'c') // crouch?
    {
		mirrorOffsetV -= mirrorOffsetVSpeed;
        cameraEyeZSpeed = -velCamara; // 
    } 

	if (cAscii == 'w'){
		flag = false;
		this->cameraEyeXSpeed = velCamara;
		this->cameraEyeYSpeed = velCamara;
	}
	if (cAscii == 's'){
		flag = false;
		this->cameraEyeXSpeed = -velCamara;
		this->cameraEyeYSpeed = -velCamara;
	}

	if (cAscii == 'd'){
		flag = true;
		this->cameraEyeXSpeed = velCamara;
		this->cameraEyeYSpeed = -velCamara;
	
	}
	if (cAscii == 'a'){
		flag = true;
		this->cameraEyeXSpeed = -velCamara;
		this->cameraEyeYSpeed = velCamara;
		mirrorOffsetH -= mirrorOffsetHSpeed;
	}
	 if (cAscii == 'j'){
		craneAngleSpeed = 3.0f;
		cambioEscena=true;
     }

     if (cAscii == 'l'){
		craneAngleSpeed = -3.0f;
		cambioEscena=true;
     }
};

void myWindow::OnKeyUp(int nKey, char cAscii)
{
    if (cAscii == 'f')
    {
        SetFullscreen(true);
    }
    else if (cAscii == 'q')
    {
        SetFullscreen(false);
    }
	if (cAscii == 'w' || cAscii == 's' ){
		this->cameraEyeXSpeed = 0.0;
		this->cameraEyeYSpeed = 0.0;
	}
	
	if (cAscii == 'a' || cAscii == 'd' ){
		this->cameraEyeXSpeed = 0.0;
		this->cameraEyeYSpeed = 0.0;
	}

	if (cAscii == 'j'){
		craneAngleSpeed = 0.0f;
		cambioEscena = false;
	}

	if (cAscii == 'l'){
		craneAngleSpeed = 0.0f;
		cambioEscena = false;
	}

	if (cAscii == 32 || cAscii =='c') // space
    {
        cameraEyeZSpeed = 0.0; // 
    }

	if (cAscii == 'b'){
		this->resetCamera();
		cameraPerspectiveType = CAMERA_WASD;
	}

	if (cAscii == 'n'){
		this->resetCamera();
		cameraEyeZ = orbitHeight;
		cameraPerspectiveType = CAMERA_ORBIT;
	}

	if (cAscii == 'm'){
		this->resetCamera();
		cameraPerspectiveType = CAMERA_CRANE;
	}
}

void myWindow::addCraneAngle(float n){
	
	this->craneAngle += n;
	while (this->craneAngle >= 360)
		this->craneAngle -= 360;

	while (this->craneAngle < 0)
		this->craneAngle += 360;

};
